tag:blogger.com,1999:blog-70170834055589560912024-03-14T11:03:39.020-07:00Kickin' down the cobblestonesDave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.comBlogger86125tag:blogger.com,1999:blog-7017083405558956091.post-63687092449909218432023-01-30T12:40:00.000-08:002023-01-30T12:40:49.620-08:00How To Get Started As an Apache Kafka Developer<!-----
Yay, no errors, warnings, or alerts!
Conversion time: 1.028 seconds.
Using this HTML file:
1. Paste this output into your source file.
2. See the notes and action items below regarding this conversion run.
3. Check the rendered output (headings, lists, code blocks, tables) for proper
formatting and use a linkchecker before you publish this page.
Conversion notes:
* Docs to Markdown version 1.0β34
* Mon Jan 30 2023 12:38:14 GMT-0800 (PST)
* Source doc: Getting Started As a Kafka Developer
----->
<h2>Getting Started as an Apache Kafka Developer</h2>
<p>
</p>
<h3>Intro – why then how</h3>
<p>
</p>
<p>
So, you’ve decided to pursue a career developing applications with Apache Kafka<sup>®</sup>. You’ve made a wise decision. Kafka is used by over 80% of Fortune 500 companies, and Kafka development ranks as one of the highest-paying job skills in IT. And besides all the practical stuff, it’s a lot of fun to work with!
</p>
<p>
</p>
<p>
Now you’re probably wondering what’s the best way to get started in this new career. In this article, we’ll discuss some tips, strategies, and resources to get you off to a great start on this exciting journey.
</p>
<p>
</p>
<h3>Developer vs. administrator</h3>
<p>
</p>
<p>
First, you should be clear about what type of Kafka work you’d like to pursue. There are a variety of roles in this space, but they mainly fall into one of two camps: developer or administrator. Since I’m a developer, that will be the main focus of this article, but if you lean more toward the administrator or operator role, you may still be able to glean some insights.
</p>
<p>
</p>
<p>
For developers, there’s a range of opportunities, such as event-driven microservices, real-time analytics, data pipelines, stream processing, and more. You can get a good feel for some of the ways to use Kafka by perusing these <a href="https://developer.confluent.io/use-case/">use cases</a>.
</p>
<p>
</p>
<p>
Once you have an idea of the type of work you’d like to do, it’s time to drill into more specifics, like programming languages, industries, and types of companies.
</p>
<p>
</p>
<h3>Lost in translation</h3>
<p>
</p>
<p>
When we talk about software development, we tend to think in terms of the language we’re most familiar with, but there is Kafka client support for many languages so I want to be careful not to make assumptions. I mean, you’re probably programming in Haskell, but you might not be 🙂. So we need to consider language options and opportunities. The client libraries that ship with Kafka are in Java and will work with most JVM languages, but there are also very good libraries available for <a href="https://developer.confluent.io/learn-kafka/kafka-python/intro/">Python</a>, <a href="https://developer.confluent.io/get-started/c/">C/C++</a>, <a href="https://developer.confluent.io/get-started/dotnet/">.NET</a>, <a href="https://developer.confluent.io/get-started/nodejs/">JavaScript</a>, <a href="https://developer.confluent.io/get-started/go/">Go</a>, and others.
</p>
<p>
</p>
<p>
The level of support and popularity of these different Kafka clients varies, with Java being the most popular and having the strongest support, both from Confluent and the community (e.g., external libraries, books, tutorials). So, if you don’t already have a preference, Java might be the way to go. A related consideration is who, in your area, is hiring and what language(s) are they using. A search on a job site, like <a href="https://www.indeed.com/">Indeed</a> or <a href="https://www.dice.com/">Dice</a>, can be helpful there.
</p>
<p>
</p>
<h3>Learning resources</h3>
<p>
</p>
<p>
Once you’ve decided on a language to focus on, it’s time to start filling those knowledge gaps. Don’t be discouraged by this step. We all have knowledge gaps, and filling them can be very rewarding. First, you’ll want to make sure you have a good understanding of Kafka basics. Fortunately, there are many resources to help you with this. A <a href="https://www.google.com/search?q=apache+kafka+books&oq=apache+kafka+books">web search</a> will turn up many great books and other resources. And, of course, <a href="https://developer.confluent.io/">Confluent Developer</a> offers interactive courses ranging from introductory (<a href="https://developer.confluent.io/learn-kafka/apache-kafka/events/">Apache Kafka 101</a>) to advanced (<a href="https://developer.confluent.io/learn-kafka/architecture/get-started/">Kafka Internals</a>), full documentation, and other content to help you get started.
</p>
<p>
</p>
<h3>The Kafka ecosystem</h3>
<p>
The Kafka ecosystem is continually growing, but there are some key components that anyone looking to work with Kafka should be familiar with.
</p>
<h4>Clients</h4>
<p>
We’ve already mentioned the clients. In whichever language you choose, there will be some code available for producing data to Kafka, consuming data from Kafka, and administering resources and configurations on Kafka brokers. Developers should be proficient with these. Aspiring administrators should be familiar with them, as they will affect how users deal with your Kafka cluster.
</p>
<h4>Kafka Connect</h4>
<p>
Kafka Connect is a framework built on top of the Kafka Producer and Consumer client libraries. It allows you to integrate external systems, such as databases, analytics engines, and SaaS applications with Kakfa using plugins, called <strong>connectors</strong>, and some configuration. There are hundreds of connectors available, but the best source of vetted connectors is the <a href="https://www.confluent.io/hub">Confluent Hub</a>. There you will find over 200 connectors with all the information you need to use them.
</p>
<h4>Kafka Streams</h4>
<p>
Kafka Streams is a Java library that provides powerful APIs and an easy-to-use DSL for building stateless and stateful event streaming applications. Kafka Streams can only be used with JVM languages, but even developers not working with a JVM language would benefit from understanding how it works and the role it plays. There are similar libraries in other languages, and an understanding of Kafka Streams will help you evaluate them.
</p>
<h4>Schema Registry</h4>
<p>
Kafka producers and consumers execute separately and don’t know anything about each other, but they do need to know about and agree upon the format of the data they are working with. This is where schemas come into play, and if you’re using schemas with Kafka, you really should be using the <a href="https://docs.confluent.io/platform/current/schema-registry/index.html">Confluent Schema Registry</a>. Schema Registry provides a way to store and retrieve schemas, as well as a means of versioning your schemas as they evolve. It works well with most Kafka client libraries and can also be accessed directly via HTTP. You can learn more about it with the <a href="https://developer.confluent.io/learn-kafka/schema-registry/key-concepts/">Schema Registry 101</a> course on Confluent Developer.
</p>
<h4>ksqlDB</h4>
<p>
As we discussed earlier, Kafka Streams is only available on the JVM, but there is another powerful tool for creating event-streaming applications with Kafka, and that is <a href="https://docs.confluent.io/platform/current/ksqldb/index.html">ksqlDB</a>. ksqlDB is an application that runs in its own cluster that allows you to build streaming applications with SQL. ksqlDB supports filtering, aggregation, transformation, and joining of event streams and tables based on Kafka topics. It’s REST API allows you to interact with those applications from just about any programming language. For more information check out <a href="https://developer.confluent.io/learn-kafka/ksqldb/intro/">ksqlDB 101</a> or <a href="https://developer.confluent.io/learn-kafka/ksqldb/intro/">Inside ksqlDB</a>
</p>
<h4>Command Line and Graphical interfaces</h4>
<p>
There are many ways to work with Kafka interactively, ranging from the shell scripts that come with Kafka to extensive graphical user interfaces. There isn’t space here to cover them all, but here are a few that are worth checking out.
</p>
<h5>Command Line</h5>
<p>
Confluent CLI - <a href="https://docs.confluent.io/confluent-cli/current/overview.html">https://docs.confluent.io/confluent-cli/current/overview.html</a>
</p>
<p>
kcat (formerly KafkaCat) - <a href="https://github.com/edenhill/kcat">https://github.com/edenhill/kcat</a>
</p>
<p>
kcctl (CLI for Kafka Connect) - <a href="https://github.com/kcctl/kcctl">https://github.com/kcctl/kcctl</a>
</p>
<h5>GUI</h5>
<p>
Confluent Control Center - <a href="https://docs.confluent.io/platform/current/control-center/index.html">https://docs.confluent.io/platform/current/control-center/index.html</a>
</p>
<p>
Conduktor - <a href="https://www.conduktor.io">https://www.conduktor.io</a>
</p>
<p>
Kafdrop - <a href="https://github.com/obsidiandynamics/kafdrop">https://github.com/obsidiandynamics/kafdrop</a>
</p>
<p>
akHQ - <a href="https://github.com/tchiotludo/akhq">https://github.com/tchiotludo/akhq</a>
</p>
<h3>Strategy</h3>
<p>
</p>
<p>
That’s a lot to learn, and it might seem overwhelming, so here’s some advice for how to build your knowledge without burning out.
</p>
<h4>Warming up</h4>
<p>
Before jumping into building Kafka applications, depending on your level of experience, it will be helpful to warm up with some introductory material, for example, the courses on Confluent Developer, such as <a href="https://developer.confluent.io/learn-kafka/apache-kafka/events/">Kafka 101</a>, <a href="https://developer.confluent.io/learn-kafka/kafka-connect/intro/">Kafka Connect 101</a>, and <a href="https://developer.confluent.io/learn-kafka/schema-registry/key-concepts/">Schema Registry 101</a>. These courses have both video and text content that provide you with a gentle introduction to these technologies. They even include exercises that allow you to get hands-on.
</p>
<h4>Working out</h4>
<p>
A great next step is to get more hands-on experience with Kafka using quick-start guides and tutorials, where a problem is presented, and you can use Kafka and your favorite language to solve it. Confluent Developer provides plenty of these. Most of the tutorials are based on <a href="https://developer.confluent.io/tutorials/">Java</a>, but there are also getting-started exercises available for <a href="https://developer.confluent.io/get-started/python/">Python</a>, <a href="https://developer.confluent.io/get-started/dotnet/">.Net</a>, <a href="https://developer.confluent.io/get-started/go/">Go</a>, and other languages.
</p>
<h4>Building a project</h4>
<p>
Now that you’ve got some experience working with and solving problems with Kafka, you can continue and accelerate your learning journey by building a project. It can be something for work, a side project, or even a cool demo idea that you can show off at a meetup (more about that in the next section). But whatever project you choose, it should be end-to-end so that you get the broadest possible experience from it.
</p>
<p>
The reason that a complete project is so much more helpful than exercises or tutorials is that the problems you are trying to solve are your own. This will provide a much stronger context for what you are learning. Context is like a hook on which to hang knowledge. Things learned without context tend to fade quickly. Just ask someone who’s been cramming for an exam.
</p>
<p>
Another benefit of building a project with Kafka is that you can use it to show what you know by hosting your project in a GitHub repository. One of the advantages that we have in the technology space is that it is much easier to show prospective employers what we are capable of, and one of the great ways to do this is via source code repositories.
</p>
<h4>Contributing to Apache Kafka</h4>
<p>
There are many opportunities for involvement in the open source Apache Kafka project. This is a great way to learn as well as to put your learning into practice. Check out the official <a href="https://kafka.apache.org/contributing">contributors' guide</a> or watch this <a href="https://www.confluent.io/resources/kafka-summit-2020/getting-started-with-apache-kafka-a-contributors-journey/">video</a> from Kafka Summit 2020 for more information and inspiration.
</p>
<h4>Certification</h4>
<p>
Another way to demonstrate your knowledge is certification. While not a silver bullet, when used in conjunction with examples of actual code you’ve written, certification can provide an extra level of comfort to prospective employers. In truth, the more valuable aspect of getting certified is the incentive it provides for learning. Confluent <a href="https://www.confluent.io/certification">provides certificates</a> for both developers and administrators, along with suggestions for how to prepare for the exams.
</p>
<h4>Show your work</h4>
<p>
Chronicling your learning journey by way of a blog can help you to learn faster by better organizing your thoughts. It can also help you to get valuable feedback from those who read it. And it’s a great way to show prospective employers what you’ve learned and your ability to communicate it.
</p>
<h3>Don’t go it alone</h3>
<p>
As you go about building your first project or preparing for your certification exam, you will undoubtedly run into questions. You can find some good answers on Google or Stackoverflow, but there is a large, active, and helpful community of developers, administrators, and just all-around good people in the Kafka community.
</p>
<p>
Getting involved in the community will make your learning journey more enjoyable and more productive. It will also provide you with invaluable networking opportunities that can lead to your first job as a Kafka developer.
</p>
<p>
The <a href="https://forum.confluent.io">Confluent Developer Forum</a> and <a href="https://www.confluent.io/community/ask-the-community/">Confluent Community Slack</a> are two great places to introduce yourself to the community, ask questions, and learn from reading others' questions and answers. You can also subscribe to the <a href="https://kafka.apache.org/contact">Apache Kafka developer and user mailing lists</a>.
</p>
<p>
But the community is about more than just learning. It’s also about helping, inspiring, collaborating, and building each other up. So, don’t just lurk, or post a question when you’re stuck. Get involved. Try to answer some questions, tell us about what you are working on, or the cool new thing you learned.
</p>
<p>
Besides the online text venues, another great way to get to know people in the community is at meetups and conferences. The <a href="https://events.confluent.io/meetups">Confluent meetup hub</a> will show you what meetups are coming up. There may be one in your area, or you can join one of the many online meetups from anywhere. As you learn, you may even consider presenting at a meetup. Most of these are recorded, and a link to your presentation could be a great addition to your CV.
</p>
<p>
Not only do members of the community help each other with technical issues, they often have valuable career advice. Here are some tips from a few <a href="https://www.confluent.io/nominate/">Community Catalysts</a>.
</p>
<p>
<a href="https://twitter.com/OlenaKutsenko">Olena Kutsenko</a> is a Senior Developer Advocate.
</p>
<p>
“Starting to work with a new technology is often tough, especially if it is as complex as Apache Kafka. Here is a list of things that I'd recommend to those who want to become an Apache Kafka developer:
</p>
<ol>
<li>Don't be afraid to ask for help. The community around Apache Kafka is knowledgeable and very friendly. So if after reading the docs and trying different approaches, you're still struggling to find a working solution for your task, don't hesitate to ask a question. Who knows, maybe the perfect solution is not so far from what you have!
<li>Don't get frustrated if the learning process is not as quick as you hoped. The Apache Kafka ecosystem is very wide and it is normal that a single person won't know all the nuances of the system. In fact, it is better to accept the fact that the learning process is never over! That's why it is so vital for us to share knowledge with each other (See the next point ;) ).
<li>Share what you learned with others. This is the best way to solidify your knowledge and get different perspectives.”
</li>
</ol>
<p>
<a href="https://twitter.com/zychr">Robert Zych</a> is a Data Platform Engineer.
</p>
<p>
“My 1st tip for anyone (regardless of programming background) interested in using Kafka is to understand when it should and shouldn’t be used. My 2nd tip would be to get/develop experience with a JVM language such as Kotlin, Java, or Scala (in that order). My 3rd tip would be to take courses and CCDAK (Confluent Certified Developer for Apache Kafka). And my 4th tip would be to experiment and build something with Kafka (preferably with helpful friends like you and <a href="https://twitter.com/nbuesing">Neil</a> 🙂)”
</p>
<p>
<a href="https://twitter.com/nbuesing">Neil Buesing</a> is a Kafka and Kafka Streams expert. He shares a few tips from the perspective of a hiring manager.
</p>
<ol>
<li>“Show interest in Kafka’s improvements (e.g. up to date on some KIPs) seeing someone being current sets them apart from others in that they can be seen as someone that “enjoys Kafka” vs just using Kafka.
<li>Operational Knowledge - I don’t need a developer to know how to manage a cluster, but understanding operational aspects is helpful; e.g. knowing that a compacted topic and how it gets compacted is useful; knowing performance issues when it comes to “commitSync()” after every reading a message — I was at a client that did a commitSync() after EVERY consumed message. This is a sign that Kafka is not well understood.
<li>If you use an additional framework be sure you know what is part of that framework vs what is Apache Kafka (e.g. KafkaTemplate is Spring Kafka not Kafka). — ok, maybe this is just a pet peeve of mine.”
</li>
</ol>
<p>
Along with the Confluent forum and slack group, you can also find many members of the Kafka community on Twitter, LinkedIn, and other social media outlets. Not only can you find help, inspiration, and potential job leads, but you can also make some great friends. This, far from complete, <a href="https://twitter.com/i/lists/1222519463532285954">Twitter list</a> can help you get started meeting some amazing people.
</p>
<h3>Practical Tips</h3>
<p>
When it comes to the actual process of looking for a job, there’s no substitute for good old-fashioned shoe leather. The more doors you knock on, the better your chances. I know that most shoes are soled with rubber these days, and you rarely walk or knock on doors when applying for jobs, but you get my meaning. Apply for as many opportunities as you can find. Even the ones that don’t turn out to be what you were looking for will provide you with valuable practice. Job hunting, and more specifically, interviewing, is a skill, and like all skills, it requires practice.
</p>
<p>
Another important point about interviews is to take careful notes of any technical questions that stumped you. Research these areas and, if possible, include what you learn in one of your projects. Remember the value of context.
</p>
<p>
As far as where to look, aside from your personal network, <a href="https://www.indeed.com/jobs?q=kafka&l=&from=searchOnHP&vjk=2ebdc72636392d9b">Indeed.com</a> is a good place to start. As of the time of this writing, they are showing over 14,000 job openings that include Kafka as a desired skill. Though not quite as large of a database, <a href="https://www.dice.com/">Dice.com</a> has also yielded good results for me in the past. Both of these sites allow you to post your CV and specify the types of opportunities you are looking for but don’t stop at that. Take the initiative to reach out to recruiters and potential employers.
</p>
<h3>Enjoy the journey</h3>
<p>
We’ve talked about a lot of things that you can do, and it may seem a bit overwhelming, but don’t look at it as a checklist, but rather a menu of opportunities for a fun adventure. Learning, experimenting, networking, blogging, presenting, and even interviewing can all be a lot of fun. There will be problems to solve, challenges to overcome, people to meet, and milestones to pass along the way. So enjoy the journey, and keep us posted. We’re rooting for you!
</p><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-72074986067292171912022-09-16T09:43:00.001-07:002022-09-16T09:43:54.625-07:00A Tech Conference at a Food Truck Park?!<p>Last week I had the pleasure of speaking at <a href="https://pybay.com/" target="_blank">PyBay Food Truck Edition</a> in San Francisco. It wasn't the first time I'd presented in a tent, but it was the first time doing so in a park surrounded by food trucks! </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgZQWvM8Hlt_0Jmhu4ROtHx1amk95XUwq9DikGwF6AzJ7xxUgYHU6Y6vBG93ruNUZZrKTf96vXfSQ4qBq4_Tdb_6JOabiLCfI3eADNvYrHXRJ4MVnyIQw9yFZQ62YSUBHJNrp2oMARKZ2UMmPH_GkI809F143pVQ14qP8VQDSHsujTymJrnd8XO9N1z" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="526" data-original-width="1000" height="168" src="https://blogger.googleusercontent.com/img/a/AVvXsEgZQWvM8Hlt_0Jmhu4ROtHx1amk95XUwq9DikGwF6AzJ7xxUgYHU6Y6vBG93ruNUZZrKTf96vXfSQ4qBq4_Tdb_6JOabiLCfI3eADNvYrHXRJ4MVnyIQw9yFZQ62YSUBHJNrp2oMARKZ2UMmPH_GkI809F143pVQ14qP8VQDSHsujTymJrnd8XO9N1z" width="320" /></a></div><br />It was a great event! The organizers and an army of volunteers took care of everything so attendees, speakers, and sponsors could enjoy the time of learning, networking, and eating! <p></p><p>My presentation on building event-driven microservices with Python and Kafka was well-received, with some great follow-up questions. </p><p><br /></p>
<br />
<blockquote class="twitter-tweet"><p dir="ltr" lang="en">Great talk on event driven micro services by <a href="https://twitter.com/daveklein?ref_src=twsrc%5Etfw">@daveklein</a> at <a href="https://twitter.com/hashtag/pybay2022?src=hash&ref_src=twsrc%5Etfw">#pybay2022</a> <a href="https://t.co/qrVGZKrhUh">pic.twitter.com/qrVGZKrhUh</a></p>— Tilia Bell (@TiliaFeels) <a href="https://twitter.com/TiliaFeels/status/1568708760885133312?ref_src=twsrc%5Etfw">September 10, 2022</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
<p>Another cool thing about this event was that we were also sponsors, which gave my co-worker <a href="https://twitter.com/thedanicafine">Danica Fine</a> and me opportunities to chat with dozens of developers and data engineers and hand out some cool swag!</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnKuvvaq_fjxFUfnDQ8WxFlUCk08xAyf3vMyboGr-rGvHinfWiapWfdlQREzvvXGKl3oCZRCUGsObk3HqaCV0W2xolqOLxi3TJ4Yet9Iy7RHjFLvtsF3PHQ5P5tY5gCDDuIodSNz7d7bVkWom8kgf4Kd3a8fNCTaUji-w_r4nlHa7edQkBWMo8xdz2/s500/pybay_booth.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="375" data-original-width="500" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnKuvvaq_fjxFUfnDQ8WxFlUCk08xAyf3vMyboGr-rGvHinfWiapWfdlQREzvvXGKl3oCZRCUGsObk3HqaCV0W2xolqOLxi3TJ4Yet9Iy7RHjFLvtsF3PHQ5P5tY5gCDDuIodSNz7d7bVkWom8kgf4Kd3a8fNCTaUji-w_r4nlHa7edQkBWMo8xdz2/s320/pybay_booth.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Sadly, I couldn't attend sessions until near the end, when visitors to our table began to slow down. At that point was able to catch an excellent talk on the observer pattern by <a href="https://twitter.com/CaiusSivjus" target="_blank">Aly Sivji</a>. </div><div><br /></div>I was also hoping to catch the testing panel that <a href="https://twitter.com/AutomationPanda" target="_blank">Andy Knight</a>, <a href="https://twitter.com/brianokken" target="_blank">Brian Okken</a>, and others were holding, but I had to miss it. At least I was able to get in on a <a href="https://twitter.com/AutomationPanda/status/1568688148645031937?s=20&t=7J7t63TBFdQWabVam1grQw" target="_blank">selfie with Andy</a>! <div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqnoaNBGI3dK7fBaWKmoN-Y5uXbOvAhBiz5Lq_ZWGFKzX8XOTZPeb4CILKH61_ouMZDWs_E0B_2hZCyle6QJYfAKzFqFX-VeWI0THMNruz49psY_o0ENnf9c86hrexi30AEzg0ygaCGRLA-wObUQadevWHA2vb5cWLP6ERDpWk-hFIgm2BjPCGUmlj/s1364/pandy_selfie.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1364" data-original-width="1024" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqnoaNBGI3dK7fBaWKmoN-Y5uXbOvAhBiz5Lq_ZWGFKzX8XOTZPeb4CILKH61_ouMZDWs_E0B_2hZCyle6QJYfAKzFqFX-VeWI0THMNruz49psY_o0ENnf9c86hrexi30AEzg0ygaCGRLA-wObUQadevWHA2vb5cWLP6ERDpWk-hFIgm2BjPCGUmlj/s320/pandy_selfie.jpeg" width="240" /></a></div><br /><div><br /></div>
<p>The weather was perfect for an outdoor event in San Francisco. The people, as seems to be the norm in the Python community, were friendly and eager to learn and to help others learn. Overall, it was a great event, and while eleven hours on my feet was a bit rough, I am so grateful for the opportunity and am already looking forward to PyBay 2023!</p></div><div><br /></div><div><br /></div>
<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-73124888361554506332022-08-17T16:22:00.000-07:002022-08-17T16:22:54.918-07:00The Joy of Community, an AnecdoteI am very grateful for the amazing people that I've met in the Apache Kafka community. Whether online or in person, my interactions with others in this community have always been rewarding.
One of the people that I met through this community is <a href="https://twitter.com/zychr" target="_blank">Robert Zych</a>. I "met" Robert at an online <a href="https://events.confluent.io/meetups" target="_blank">Kafka Meetup</a> that we were both attending. Robert was one of the first to turn on his camera and get involved in the discussion. He was very interested in learning more about Kafka, and others in the community, such as <a href="https://twitter.com/nbuesing" target="_blank">Neil Buesing</a>, <a href="https://twitter.com/MatthiasJSax" target="_blank">Matthias Sax</a>, and <a href="https://twitter.com/jbfletch_" target="_blank">Anna McDonald</a>, to name a few, were eager to help him. <div><br /></div><div>As time went on, I was able to get to know Robert better. We even worked together on an interesting side project that he came up with. And Robert became more involved in the community. He went on to write a <a href="https://www.confluent.io/blog/getting-started-with-apache-kafka-in-python/" target="_blank">guest blog post</a> for the Confluent blog, and was even selected as a Confluent Community Catalyst!
Then a while back, Robert asked me for my mailing address. About a week later, this lovely tie showed up in the mail.</div><div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxTdejtdIxM1PGGTSN6t_9tyVdkLkXmwy1LvI73BwHTXzUSVJaFhUanC0X--uqBrNvLWp0HXcMstnMpmqmoz0rIcfb00cD3XJEeFDnHjDFpHSitKr-3zG6LsEk7nJSEvLzvAthOb1gB5TBkNj9uYNSaa_-COAwyI2D8_a_LRVO7oseqkz12kkkQYtZ/s577/avocado_tie.jpg" style="clear: left; display: block; float: left; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="577" data-original-width="288" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxTdejtdIxM1PGGTSN6t_9tyVdkLkXmwy1LvI73BwHTXzUSVJaFhUanC0X--uqBrNvLWp0HXcMstnMpmqmoz0rIcfb00cD3XJEeFDnHjDFpHSitKr-3zG6LsEk7nJSEvLzvAthOb1gB5TBkNj9uYNSaa_-COAwyI2D8_a_LRVO7oseqkz12kkkQYtZ/s320/avocado_tie.jpg" /></a></div>
Now, I don't wear ties very often, but I will probably make an exception for this one. Some of you might notice the avocado pattern on this tie, and might <a href="https://www.marythengvall.com/blog/2018/1/31/developer-avocados-the-good-kind-of-fat" target="_blank">tie it to the fact that I am a developer advocate</a> at Confluent. But that's only because you don't know the rest of the story. </div><div><br /></div><div> Frequently, at Kafka meetups, we'll start out by asking people where they are connecting from. In the before times, meetups were location-based, but now people join from all over the world. (I like to attend meetups from Australia, so I can find out how tomorrow is looking.) At one of these events, Robert mentioned that he is in Sacramento, California. I grew up in Sacramento and still have family there, so when I mentioned to Robert that I was going to attend a nephew's wedding, he invited me to lunch on the afternoon before the event. He lived nearby the wedding venue, so it worked out great. </div><div><br /></div><div>We had a great time meeting in person and catching up.
Now I was already dressed for the wedding in slacks and a white dress shirt. No tie, because, well, I don't wear ties. So, I was being very careful, even ordering something that I knew was not likely to drip and make a mess of my white shirt. However, Robert had ordered some delicious-looking guacamole and chips, and I just had to try some.</div><div><br /></div><div>Of course, on my very first attempt, a blob of said delicious-looking guac fell right on my shirt!
There was a small, but very noticeable green stain that I couldn't get rid of, and there was only a couple of hours until the wedding. Fortunately the stain was right in the center of the shirt, where a tie would normally go. So, Robert invited me over to his house, where I was able to not only meet his lovely family, but borrow a tie that perfectly covered the guacamole stain!
When I received the package in the mail from Robert, and saw the pattern of the tie, I almost fell over laughing. The double meaning was obvious to me, and now it is to you too, because now you know... the rest of the story.
<br />
<br /><br />
* My sincere apologies to the memory of <a href="https://en.wikipedia.org/wiki/Paul_Harvey" target="_blank">Paul Harvey</a>.</div><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-79348888721816827022020-08-03T20:00:00.007-07:002020-08-12T18:26:47.193-07:00Using Kafka Streams Interactive Queries to Peek Inside of your KTables<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
<p>Recently we found a bug in one of our Kafka Streams applications, and as I was looking into it, I found that we had a <br/><code>Stream -> Table</code> left join that was failing. This didn't make sense, as every indication was that the data, with the correct key, should have been in the KTable at the time that the join was attempted.</p>
<p>So, I set out to verify that. It was easy to see what was in the stream, but I was struggling to figure out how to see what was in the table. Using <a href="https://github.com/edenhill/kafkacat" target="_blank">Kafkacat</a>, I could see that the data was in the underlying topic, but I needed to see that in context with the KTable at runtime.</p>
<p>That's when I turned to the helpful geniuses on the <a href="https://launchpass.com/confluentcommunity" target="_blank">Confluent Community Slack</a> group. On there, someone suggested that I use an interactive query.</p>
<p>Now, to some, this might be a no-brainer, but I am still somewhat new to Kafka and had never used interactive queries. But there's a first time for everything, so I dug into it.</p>
<p>I guess I shouldn’t have been surprised by how easy it was, but Kafka Streams never ceases to amaze me. The following bit of code is all it took to give me a view inside my KTable:</p>
<script src="https://gist.github.com/daveklein/9943ee266a39c5b2bf361d21a40d319e.js"></script>
<p>Let's walk through this code.</p>
<p>(Line 3) First off I needed to get a hold of the <code>KafkaStreams</code> instance, in order to access the state store.</p> <p>Since the bit of topology that I’m working on is in a different Java class from the one where the stream is created and launched, I have to make a call to get it.</p>
<p>(Line 4) To access the state store, I needed its name, so I called <code>queryableStoreName()</code> on the KTable.</p>
<p>(Line 5) Now I can get a hold of the state store itself, in the form of a <code>ReadOnlyKeyValueStore</code>, using <code>KafkaStream</code>'s <code>store()</code> method.</p>
<p>(Line 6) To see all of the records in the store, I used a <code>KeyValueIterator</code> that is returned from the <code>store.all()</code> method.</p>
<p>(Line 7-10) For each record, I print the key and value, and then, on line 11, I close the state store. </p>
<p>I bundled that all up in a handy method called <code>queryKTableStore()</code>.</p>
<script src="https://gist.github.com/daveklein/e7e41efa89dcaec0aee9eb380436e3c1.js"></script>
<p>Now I was able to add a <code>peek()</code> statement, calling this method, to my topology, right before the leftJoin that was failing.</p>
That gave me output like this:
<code>
key: 10001 Widget: {id:10001, name: Winding Widget, price: 299.95}<br/>
key: 10002 Widget: {id:10002, name: Whining Widget, price: 199.95}<br/>
key: 10003 Widget: {id:10003, name: Wonkey Widget, price: 499.95}
</code>
<p>And of course, the key I was trying to join on, <code>10004</code>, was not in the store, which means that it was not in the <code>KTable</code>. I added another <code>peek()</code> call after the failed join attempt, and now the output was more like this:</p>
<code>
key: 10001 Widget: {id:10001, name: Winding Widget, price: 299.95}<br/>
key: 10002 Widget: {id:10002, name: Whining Widget, price: 199.95}<br/>
key: 10003 Widget: {id:10003, name: Wonkey Widget, price: 499.95}<br/>
key: 10004 Widget: {id:10004, name: Wonder Widget, price: 999.95}
</code>
<p>Now it's there! Mystery solved! I have a timing problem on my hands... which is another mystery, but one for a different post. For now, I just wanted to point out this simple and powerful feature of <a href="https://kafka.apache.org/documentation/streams/" target="_blank">Kafka Streams</a>.</p>
<p>Before leaving I also wanted to point out that that the <code>ReadOnlyKeyValueStore</code> is limited to one application instance. In my case, running locally, I only had one instance, but in a distributed environment, things could get more complicated. Also, <code>ReadOnlyKeyValueStore</code> has another method for accessing data by key, if you already know the key. <code>store.get(key)</code> will return the value if it exists for that key. Of course there is more you can do and you can learn more about it in the <a href="https://kafka.apache.org/10/documentation/streams/developer-guide/interactive-queries.html" target="_blank">Developer's Guide</a></p>
<script src="https://raw.github.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>
</div>
<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-12726312895955778832020-05-27T10:50:00.000-07:002020-05-27T15:30:44.902-07:00Online Meetups Are Different, But Still A Valuable ResourceI’ve always been a fan of user groups, which are now mostly known as meetups. In the past I’ve led Java and Groovy user groups, and they were always rewarding experiences.<br />
<br />
More recently, I’ve been helping to organize the <a href="https://www.meetup.com/Saint-Louis-Kafka-meetup-group/" target="_blank">St. Louis Apache Kafka Meetup</a>, hosted by Confluent. We only had one in-person meeting before the COVID-19 rules came into play, and we had to convert subsequent meetings to online. <br />
<br />
I was pretty bummed, thinking that online meetups would just be like webinars, or maybe recorded conference videos, which are great, but nothing like a live event. Now, after attending over a dozen online meetups around the world, I have to say I was pleasantly surprised. <br />
<br />
The Confluent Community team does an excellent job of running these Zoom meetups. At the start of the meetup, everyone can be unmuted, so there is a great time of networking and catching up with friends, old and new. Then the host mutes the audience and the presenter gets started. During the presentation, attendees ask questions in the chat. Some presenters will pause to answer questions along the way, others will answer them at the end, but I have yet to see a question go ignored. <br />
<br />
After the presentation, the host allows attendees to unmute again, and the discussions are just what you’d expect with an in-person meetup, except the participants might be in another country! <br />
<br />
Another bonus for Confluent’s online meetups is that they are recorded. You can watch videos from over twenty meetups from the past few months, on the <a href="https://events.confluent.io/meetups" target="_blank">Confluent Meetup Hub</a>. This site is a treasure trove, not just for the recordings, but because it also shows you which meetups are coming up, so you can join them live. <br />
<br />
When you do join one of these online meetups, and I’m sure you will, you should consider turning on your video, if possible, and introducing yourself. The Apache Kafka community is made up of some of the friendliest people I’ve ever met, so I can guarantee that you will be welcomed! If you continue attending meetups in a particular time zone, you will get to know the regulars and even become one yourself. <br />
<br />
So, while I still miss the in-person meetups, and I am looking forward to them returning, I am very grateful for the online meetups as well, and at the risk of being greedy, I am hoping, in the future, that we can have both! <br />
<br />
And, speaking of in-person meetups, there are Apache Kafka meetups all over the world. Find the one closest to you at <a href="https://www.confluent.io/community">https://www.confluent.io/community</a>. I would encourage you to join one (or more) of the meetup groups, so that you will hear when in-person meetups are beginning again. <div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-3993704835126404992020-03-04T07:38:00.000-08:002020-03-04T10:24:44.763-08:00Saint Louis Apache Kafka® Meetup by Confluent<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
One of the many ways that <a href="http://developer.confluent.io/" target="_blank">Confluent</a> supports the developer community is by hosting Meetups around the world. For example, they just had <a href="https://twitter.com/tlberglund" target="_blank">Tim Berglund</a> out in Paris (poor guy) for what looks like a <a href="https://twitter.com/LoicMDivad/status/1235101753571409920?s=20" target="_blank">great event</a>!</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
They also host a meetup right here in <a href="https://www.meetup.com/Saint-Louis-Kafka-meetup-group" target="_blank">St. Louis</a>, and they've given me the great privilage of helping to organize it. </div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
All that to say this: </div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
Save the date! On <b>Tuesday, March 24th</b>, we will have two great presenters at the Saint Louis Apache Kafka Meetup!</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
<a href="https://twitter.com/mr_mitchellh" target="_blank">Mitch Henderson</a>, a Technical Account Manager par excellence with Confluent, will talk about how to make our Kafka installations fault-tolerant, even to the datacenter level.</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
After that, <a href="https://twitter.com/nbuesing" target="_blank">Neil Buesing</a>, the Director of Real-time Data at <a href="https://objectpartners.com/" target="_blank">Object Partners</a>, will show us how to build a web application using Kafka and Kafka Streams as our database. Prepare to have your mind blown on this one!</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
This is going to be a packed meeting, but we'll have plenty of pizza and soft drinks on hand in case it runs long. So, if you're in the St. Louis area, or can get to the St. Louis area (you know you've always wanted to visit), please plan on joining us March 24th, at 6pm. All of the details can be found on our <a href="https://www.meetup.com/Saint-Louis-Kafka-meetup-group/events/268782979/" target="_blank">Meetup page</a>.</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
Oh, and you can <a href="https://twitter.com/kafkastl" target="_blank">follow us</a> on Twitter too.</div>
<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-68998537573953752892020-02-12T07:41:00.000-08:002020-02-12T07:41:55.865-08:00Confluent KSQL Workshop in Saint LouisRecently <a href="https://www.confluent.io/" target="_blank">Confluent</a> and <a href="https://www.wwt.com/" target="_blank">World Wide Technology</a> held a hands-on workshop on Stream Processing with KSQL. <a href="https://www.confluent.io/kafka-summit-ny19/zen-and-the-art-of-streaming-joins/" target="_blank">Nick Dearden</a>, from Confluent, led the training and did an excellent job. He gave a very clear introduction to the problem space, and the role that KSQL plays. <br />
<br />
Then we launched into the hands-on lab. Wow! I have never been to a hands-on that was so smooth.<br />
<br />
There were 50 students in the rooms and each of us had a pre-assigned AWS user account, with which we could ssh into a server running KSQL and MySQL. There was a data generator running, I believe using the <a href="https://github.com/confluentinc/kafka-connect-datagen" target="_blank">Kafka Connect Datagen</a> connector (though I could be wrong on that). So, everything was ready to go and we were all working through the exercises within minutes. <br />
<br />
Along the way, if anyone got stuck, <a href="https://www.linkedin.com/in/brianlikosar/" target="_blank">Brian Likosar</a> and <a href="https://www.linkedin.com/in/cliffgilmore/" target="_blank">Cliff Gilmore</a> were on hand to help out. From what I could see, nobody was stuck for long.<br />
<br />
The exercises were simple, yet detailed enough to show some of the cool features of KSQL. I had seen several video demos of KSQL before, but this was my first time trying it out. It was pretty fun. <br />
<br />
For me the highlight—beyond just being in a room with so much Kafka brainpower—was when we ran <span style="font-family: Courier New, Courier, monospace;"><b>explain</b></span> on one of the queries we had written, and lo and behold, there's the KStream topology! I guess I should have figured this, but it was still cool to see. KSQL is basically a really slick <a href="https://kafka.apache.org/documentation/streams/" target="_blank">Kafka Streams</a> app.<br />
<br />
So, the workshop was fun and informative, and KSQL is a pretty powerful tool, especially for those who are not living in the JVM. But the real take-away, for me, was that the Kafka Streams API is amazing!<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-15785121559957341922020-02-11T15:44:00.000-08:002020-02-11T16:18:44.695-08:00Spock: Expect two calls from one method with specific results.<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
This is probably nothing new to many people, but it was a very pleasant surprise to me, so I'm posting here in case there are others as clueless as I. </div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
Here's the situation. I've got a method under test, in Spock. (Yay! <a href="https://groovy-lang.org/" target="_blank">Groovy</a>!) There is a mocked class that has a method that will be called twice, so we want to expect that, and we need to specify the return results because they are used by the method under test. In some scenarios, the expected params are known and easy to construct in the test, like a String literal. This is the easy one.</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<script src="https://gist.github.com/daveklein/82457afeb2a27846b812d1cff35c8fc4.js"></script>
<br />
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
However, in some scenarios, the expected params are more difficult to construct in the test code, and I still want to expect the two calls in a specific order and with specific return values—which, again, are used downstream.</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
This is where I was stumped. My very limited Spock skills came back to haunt me, and Google failed to hide my ignorance. No worries: I'm working on a project with the brilliant (and helpful) developers from <a href="https://objectpartners.com/" target="_blank">Object Partners</a>, and <a href="https://objectpartners.com/author/nbuesing/" target="_blank">Neal Buesing</a> came up with this little gem.</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<script src="https://gist.github.com/daveklein/a5dd162926bbb4f016133f2effce5317.js"></script>
<br />
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
Needless to say, it worked like a charm, and kept me from cluttering up the test with a ton of code to construct the complex objects that would have been needed.</div>
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal; min-height: 14px;">
<br /></div>
<br />
<div style="font-family: Helvetica; font-size: 12px; font-stretch: normal; line-height: normal;">
So, if you're reading and didn't know about this trick, tuck it away for later, and you won't have to admit to the world that you were stumped.</div>
<script src="https://raw.github.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>
<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-76161813419840633602020-02-07T06:10:00.000-08:002020-02-22T17:33:01.669-08:00Pass me another cup of Kafka Kool-AidOk, I admit it. I have thoroughly imbibed the event-driven Kool-Aid.<br />
<br />
It all started with a new job. This new job would involve Java development (I miss Groovy), and we were going to be using something called "Kafka". So, before the job began, I started looking into Kafka. I soon made the connection that my good friend, <a href="https://twitter.com/tlberglund">Tim Berglund</a>, works for the company founded by the creators of Kafka, <a href="https://www.confluent.io/">Confluent</a>. Tim and his colleagues have produced a seemingly endless supply of resources to help people like me understand this amazing new world. (Hmm... I wonder if there is a name for a barista who makes Kool-Aid instead of coffee?)<br />
<br />
Anyhow, after watching several of the short Confluent videos, I graduated to conference recordings from <a href="https://www.confluent.io/resources/kafka-summit-san-francisco-2019/">Kafka Summit</a>. Wow! It was like I'd reached the Kool-Aid bottling plant! So much good information by such good presenters. I can't wait to attend one of these in person!<br />
<br />
Then the job started. To my surprise, I found that I'd be working with consultants from <a href="https://objectpartners.com/">Object Partners</a>. I was familiar with OPI (as we affectionately call them) from the good ol' days of <a href="https://objectpartners.com/page/2/?s=Grails">Grails</a>, so it was great to know that they were also working in this amazing space. I guess someone at OPI knows how to pick great technologies!<br />
<br />
The team from OPI has been a tremendous help and encouraged me to dive right in. So, I have. I'm currently working on my first <a href="https://www.confluent.io/stream-processing/" target="_blank">Kafka Streams</a> story, and <a href="https://twitter.com/daveklein/status/1225430678856257536" target="_blank">having a blast!</a><br />
<br />
There are so many other great resources and friendly, helpful, and brilliant people that I could talk about. I hope to write more here, as I continue to learn and enjoy this refreshing beverage. For now, I'll just pour another cup and get back to coding.<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-59171056924904765792014-01-27T20:35:00.000-08:002014-01-27T20:35:14.025-08:00And the winners are…<div>
<span style="font-family: inherit;">Congratulations to the five winners of <i>Grails 2: A Quick-Start Guide</i>! We had some very clever entries, but we only have 5 books to give away, so we had to make some hard choices. The winners are: </span></div>
<blockquote class="twitter-tweet" lang="en">
assert "Grails 2: A Quick-Start Guide!" == Book.where{grails.version==2}.list(order:asap).first()
<a href="http://t.co/liNPj0mzT7">http://t.co/liNPj0mzT7</a>
<a href="https://twitter.com/search?q=%23grails&src=hash">#grails</a> <a href="https://twitter.com/search?q=%23GQuick2&src=hash">#GQuick2</a><br />
— YeIIowsnow (@yeIIowsnow) <a href="https://twitter.com/yeIIowsnow/statuses/425317814388289536">January 20, 2014</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<blockquote class="twitter-tweet" lang="en">
Grails(2).searchFor.isOver "The Pragmatic Bookshelf | Grails 2: A Quick-Start Guide" <a href="https://twitter.com/pragpub">@pragpub</a> <a href="http://t.co/memYIwze37">http://t.co/memYIwze37</a><br />
— topchimp (@topchimp) <a href="https://twitter.com/topchimp/statuses/425328954078408705">January 20, 2014</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<blockquote class="twitter-tweet" lang="en">
He who is valiant and pure of spirit may find the holy <a href="https://twitter.com/search?q=%23Grails&src=hash">#Grails</a> in the Castle of Aaauuuggghhh... <a href="http://t.co/VRuaUi3Dxc">http://t.co/VRuaUi3Dxc</a><br />
— Gregg Bolinger (@GDBolinger) <a href="https://twitter.com/GDBolinger/statuses/426039046670794752">January 22, 2014</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<blockquote class="twitter-tweet" lang="en">
2 Quick 2 Furious 2 Grails 2 - GQuick2 - <a href="http://t.co/ApRwR8r7ir">http://t.co/ApRwR8r7ir</a><br />
— Tomas Lin (@tomaslin) <a href="https://twitter.com/tomaslin/statuses/426085692548976640">January 22, 2014</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<blockquote class="twitter-tweet" lang="en">
After reading 15 reasons I should use Grails <a href="http://t.co/btGSbs0Uqt">http://t.co/btGSbs0Uqt</a>, I need a copy of Grails 2: A Quick-Start Guide <a href="http://t.co/0ul7Evtjiu">http://t.co/0ul7Evtjiu</a><br />
— Vinny Carpenter (@vscarpenter) <a href="https://twitter.com/vscarpenter/statuses/426158135812698112">January 23, 2014</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<div>
<span style="font-family: inherit;">If you are one of the winners, please send a Twitter direct message to <a href="https://twitter.com/daveklein">@daveklein</a> with your shipping address. </span></div>
<div style="min-height: 14px;">
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Thank you to all who participated!</span></div>
<div style="min-height: 14px;">
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Dave</span></div>
<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-48652927704288617792014-01-20T08:15:00.001-08:002014-01-20T08:20:03.419-08:00Win a copy of Grails 2: A Quick-Start Guide!Now that <i>Grails 2: A Quick-Start Guide</i> (affectionately known as GQuick2) is in print, we are looking to helpful blog readers (and Twitter readers) for help in getting the word out. Participating readers will have a chance at winning a paper copy!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHJ4Xp9YmloqJwZyqWf9ukp4mB7-kiZbtyR4rRGNqgPd2nwU6xc1bL_KIu2mGjR1yJ4Uu1vneD_d_OINDNjgi_KvKDRMuGoP3o9gLHApGe4WQDjchG5wEp7-yk37Ew5ZA2oKH-V6U4f4w/s1600/IMG_1646.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHJ4Xp9YmloqJwZyqWf9ukp4mB7-kiZbtyR4rRGNqgPd2nwU6xc1bL_KIu2mGjR1yJ4Uu1vneD_d_OINDNjgi_KvKDRMuGoP3o9gLHApGe4WQDjchG5wEp7-yk37Ew5ZA2oKH-V6U4f4w/s1600/IMG_1646.JPG" height="480" width="640" /></a></div>
<br />
<b>From now until Monday, January 28, you can enter the GQuick2 Twitter Giveaway.</b><br />
<br />
We are giving away five copies of the book. To enter:<br />
<br />
<ol>
<li><b>Post a tweet mentioning the book and linking to its page</b> on the Pragmatic Bookshelf site. For your convenience, here is a link you can use: <a href="http://bitly.com/GQuick2">http://bitly.com/GQuick2</a></li>
<li>Tweets will be judged based on <b>creativity and uniqueness</b>.</li>
<li>On Monday, the 28th, <b>we will announce the top five</b> tweeters based on those criteria, and each of them will get a paper copy of the book!</li>
</ol>
<div>
<br />
You are welcome to tweet more than once. Each tweet will be entered in the contest and evaluated. So, put on your thinking caps, get a cup of coffee to get those creative juices flowing and start tweeting! </div>
<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-38864170496910869402014-01-16T06:07:00.000-08:002014-01-16T06:09:50.171-08:00Introducing Grails 2: A Quick-Start GuideNow there’s a great way to get up to speed quickly with Grails 2.3! <i>Grails 2: A Quick-Start Guide</i> is finally done and available.<br />
<br />
It’s the same fun, fast-paced tutorial that garnered reviews like <a href="http://www.amazon.com/review/R251G4G8RWQ767/ref=cm_cr_dp_title?ie=UTF8&ASIN=1934356468&nodeID=283155&store=books%E2%80%9D">“Mr. Klein's easy writing style and terrific examples gave me a clear understanding of the power of Grails and allowed me to see for myself what all of the buzz is about. Great book. Highly recommended”</a> and <a href="http://www.amazon.com/review/R1CH393VKDJUY0/ref=cm_cr_dp_title?ie=UTF8&ASIN=1934356468&nodeID=283155&store=books%E2%80%9D">“The best 200 pages of technical literature I have ever read. This is a true 'No Fluff Just Stuff' book.”</a><br />
<br />
We’re still working through the process of building an app from start to finish, but now we're doing it entirely with Grails 2.3. So, if you're looking to get started with this powerful and popular web framework — or want to help another developer get up to speed — you really should take a look at <i>Grails 2: A Quick-Start Guide</i>. On the publisher's site, at <a href="http://bit.ly/GQuick2">bit.ly/GQuick2</a>, you can view the table of contents and even download one of the first chapters.<br />
<br />
So, check it out and let us know what you think.<br />
<br />
Thanks!<br />
Dave and Ben<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-67927628883120952182011-12-12T08:32:00.000-08:002011-12-12T08:56:33.374-08:00Grails: A Quick-Start Guide is backNo, there isn’t a second edition (yet). But some may have noticed that the ebook of <a href="http://pragprog.com/book/dkgrails/grails"><em>Grails: A Quick-Start Guide</em></a> (or GQuick) was no longer available on The Pragmatic Programmers’ site. The thought was that it was becoming obsolete. But after several requests from developers who are still getting started with the Grails 1.<em>x</em> framework, the publisher decided to make it available for a while longer.<br /><br />Once Grails 2.0 is out and beginning to be widely adopted, GQuick will probably be retired. But for now, it remains one of the best options for developers wanting to quickly take advantage of the powerful Grails framework.<br /><br />The publisher is no longer printing copies of GQuick, but if you really want a copy of the dead-tree edition, you can find one on <a href="http://www.amazon.com/product/dp/1934356468/">Amazon.com</a>. (The price seems to be climbing, though. Currently, <a href="http://www.amazon.com/gp/offer-listing/1934356468/ref=dp_olp_new?ie=UTF8&qid=1323707896&sr=1-4&condition=new">new copies</a> are going for $54.39, and <a href="http://www.amazon.com/gp/offer-listing/1934356468/ref=dp_olp_used?ie=UTF8&qid=1323707896&sr=1-4&condition=used">used copies</a> for $48.85.)<br /><br />For those who have asked, I am working on a Grails 2 intro book (publisher to be determined). Stay tuned.<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com1tag:blogger.com,1999:blog-7017083405558956091.post-69976252843709158032011-07-19T07:13:00.000-07:002011-07-19T08:17:40.390-07:00CocoaConf, And My AnniversaryFor the past few months, my sons and I have been working on a <i>different</i> kind of project: We are putting on a conference for developers on Apple platforms, such as iPhone, iPad, and Mac. It’s called <a href="http://cocoaconf.com/">CocoaConf.</a><br /><br />The first <a href="http://cocoaconf.com/">CocoaConf</a> is being held in Columbus OH, on August 12 - 13, 2011. We have an exciting line-up of speakers, including <a href="http://dimsumthinking.com/">Daniel Steinberg</a>, <a href="http://bill.dudney.net/roller/objc/">Bill Dudney</a>, <a href="http://www.subfurther.com/blog/">Chris Adamson</a>, <a href="http://juddsolutions.blogspot.com/">Christopher Judd</a>, and <a href="http://www.arbormoon.com/">Dave Koziol</a>.<br /><br />We will be having three tracks for the two days; this will include an <a href="http://www.cocoaconf.com/session/details/4">all day hands-on iPhone workshop</a> on the first day. It's shaping up to be a very exciting event.<br /><br />The idea for this conference came when my #3 son, Solomon, began learning Mac programming using the book <a href="http://pragprog.com/book/tibmac/beginning-mac-programming"><i>Beginning Mac Programming</i></a> by Tim Isted. Taking inspiration from my favorite conference series of all time — <a href="http://nofluffjuststuff.com/">No Fluff, Just Stuff</a> — we began tossing around ideas. The NFJS events are known for a capped size so that they don't feel crowded, and for a focus on technical content, without the vendor hype and special events that other conferences tend to have. So that's what we are doing for <a href="http://cocoaconf.com/">CocoaConf</a>.<br /><br />I hadn't blogged about <a href="http://cocoaconf.com/">CocoaConf</a> here since it has nothing to do with my usual topics, <a href="http://groovy.codehaus.org/">Groovy</a> and <a href="http://grails.org/">Grails</a> (although the CocoaConf site <i>is</i> being developed in Grails). But today I am going ahead with this post, so that I have a place to explain a crazy (but fun) idea.<br /><br />You see, 26 years ago today, my beautiful wife, Debbie, said “I do.” And today, we are celebrating this 26th anniversary with <b>a one-day-only <a href="http://cocoaconf.com/">CocoaConf</a> discount of 26% off the current early-bird rate of $350</b>. That's a $91 savings for today (July 19th) only! So: If you are interested in developing for the iPhone/iPad or Mac and can make it out to Columbus in August, <b>you can now sign up for CocoaConf for only $259</b> — but only for today, July 19, 2011. Just go to <a href="http://cocoaconf.com/register">http://cocoaconf.com/register</a> and use the coupon code “ANNIVERSARY”.<br /><br />I don't know if anyone will take advantage of this deal, but I thought it would be a fun way to celebrate 26 wonderful years of marriage to my amazing wife. She is the second best thing God has ever done for me!<div><br /></div><div>(And finally, I'll leave you with a bit of child exploitation. Here's our #13, Joshua, telling us where he's headed in August.)</div><div><br /></div><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzpJblbMU5k3NmKU7TzXs5rNQq_a-1zw7yzWgPSmZd_wlo7XKMQm7fgwN8npo6CDrcAVcpqpi2pgz_JhKhNAw' class='b-hbp-video b-uploaded' frameborder='0'></iframe><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com2tag:blogger.com,1999:blog-7017083405558956091.post-2973855612854028962011-01-25T12:57:00.000-08:002011-01-25T18:46:31.289-08:00Groovy / Grails User GroupsTechnology user groups benefit both <i>a technology</i> (with the companies behind it) and <i>its users</i>. Java user groups around the world played a big role in the adoption and advance of the Java language and platform. Even now that Java is in its old age (or on its deathbed, depending on who you talk to), JUGs are actively promoting educational and community-building initiatives.<br /><br /><b>The Groovy community is benefiting similarly from a growing number of user groups.</b> There are currently a few dozen groups around the world, and more are forming every day.<br /><br />Now <b>there is a website that can help you find a group in your area or help you get one started</b>. <a href="http://g2groups.net/">G2Groups.net</a> has a list of active Groovy user groups, with links to their sites. If you can't find one in your area, you can propose one. The site will post a link to your proposal on <a href="http://twitter.com/g2groups">Twitter</a>; you can retweet this to help get the word out. Then when others are interested in your idea, you'll get emailed about it, and you're off and running!<br /><br />Once you get a few likeminded (and by "likeminded," I of course mean "brilliant") people together and get a group started, send me a note, and <b>I'll invite you to the <a href="http://groups.google.com/group/gugleaders">Groovy User Group Leaders</a> list on Google Groups</b>. This list is a great way to get support and ideas from other Groovy/Grails/Griffon/Gaelyk/Gradle/Getc. group leaders.<br /><br />I've always said that the best feature of Groovy and Grails is the community. User groups are a big part of that. So if you're not already involved in a G2Group, <a href="http://g2groups.net/">get plugged in</a>. You'll be glad you did.<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com4tag:blogger.com,1999:blog-7017083405558956091.post-68176725925294561002010-10-23T15:49:00.000-07:002010-10-27T06:26:56.630-07:00JavaOne Has Been ReplacedI just got back from <a href="http://www.springone2gx.com/conference/chicago/2010/10/home">SpringOne/2GX</a>. It was an excellent experience. The enthusiasm and interest level of the attendees was great. The content, both on the Spring side and (of course) the <a href="http://groovy.codehaus.org">Groovy</a> and <a href="http://grails.org">Grails</a> side, was top-notch. There were nine tracks loaded with sessions that covered all kinds of topics related to software development in the Java ecosystem. There were long breaks with plenty of stimulating hallway conversations. Even the keynotes were informative. At most conferences, I skip the keynotes. I've become so used to them being just sales pitches from people who don't even use the tools they're talking about. That wasn't the case here. One of the highlights of the show was Graeme Rocher's keynote demo of <a href="http://blog.springsource.com/2010/09/07/announcing-gorm-for-redis/">the new NoSQL DB support in GORM</a>. <br /><br />As excellent as it was, I'm not saying that SpringOne/2GX has replaced JavaOne.<br /><br />The week before SpringOne/2GX, I took two of my sons to <a href="http://strangeloop2010.com">the StrangeLoop conference in St. Louis</a>. This conference covered several important areas of software development. There was good coverage of Java and alternate JVM languages and frameworks, along with a bunch of other languages and technologies. It wasn't held in a big conference center or a nice hotel, but in three different buildings, each with a unique atmosphere. This “small” midwest conference featured industry luminaries that you might have expected to see only in the Moscone Center. To see them <a href="http://www.flickr.com/photos/wondible/5089025865/">on the stage of a St. Louis night club</a> was something else! <br /><br />Just this afternoon, after opening registration less than 4 days ago, <a href="http://www.codemash.org/">the CodeMash conference in Sandusky, OH</a>, sold out. This conference, like StrangeLoop, covers a broad range of technologies. Though there is a bit more .NET than I would like to see, :-) it is another excellent event, bringing speakers from across the country and attendees from across the globe. <br /><br />I could go on. There is the <a href="http://www.siliconvalley-codecamp.com/">Silicon Valley Code Camp</a>, the <a href="http://www.houstontechfest.com/">Houston TechFest</a>, and so many more. But you get the picture.<br /><br />For several years now, JavaOne has been turning into more of a vehicle for pushing a certain technology (<span style="font-style:italic;">cough<span style="font-weight:bold;">JavaFX</span>cough</span>). The attendance has been gradually dropping. As developers stopped going to JavaOne, they began to find other events to meet the need that JavaOne was not filling. Or they started their own. <br /><br />The Oracle acquisition and the subsequent decision to make JavaOne an afterthought to Oracle's annual event didn't help, but JavaOne was already on its way out. It was destroyed the way so many companies are: by <span style="font-weight:bold;">pushing what it wanted its customers to have</span> rather than <span style="font-weight:bold;">providing what its customers wanted</span>.<br /><br />So I can't point to a single conference that will be the new JavaOne (although <a href="http://dave-klein.blogspot.com/2010/06/uberconf-exceeding-expectations.html">Über Conf comes close</a>). But I <span style="font-style:italic;">can</span> look out at all the technical gatherings happening around the world—<a href="http://www.devoxx.com/display/Devoxx2K10/Home">Devoxx</a>, <a href="http://gotocon.com/aarhus-2010/">JAOO</a>, <a href="http://www.jaxindia.com/">the</a> <a href="http://jaxlondon.com/2010s/">JAX</a> <a href="http://jax.de/">events</a>, the <a href="http://gr8conf.org/">GR8 events</a>, and so many more. And then I can look closer to home and see all the “small” conferences that are providing big benefits to attendees and speakers, and I can say it without a doubt. <span style="font-weight:bold;">JavaOne has been replaced.</span><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com7tag:blogger.com,1999:blog-7017083405558956091.post-76065415140505434472010-10-09T10:35:00.000-07:002010-10-09T15:05:53.892-07:00Move On In PeaceAs long as we measure the success of a movement by adoption numbers, any successful movement will eventually become compromised and diluted. This is a cycle that has repeated itself time and again. It happens in all areas of human interaction: politics, religion, science, entertainment, business, and technology, to name a few.<br /><br />When this cycle occurs, the founders and early adopters often begin to feel bitter about where things have gone. They long for the “early days.” They begin to lash out at the masses that have morphed their creation into something less than what they had in mind. They may even make a concerted effort to reform the movement, and to bring it back to its roots. This is understandable, but it is not practical. I cannot think of a single instance where it has worked.<br /><br />I've been thinking of a more sane and peaceful path: Founders and early members of a movement could, at the first sign of success, begin to plan their next move. Learn from what has been done before. Keep the essence of it, and start over. If the original idea was good, reuse and rebrand it. If those unwashed masses did bring a little value after all, borrow it and build on it. Or scrap the whole mess and reinvent the wheel. (Round does get boring after a while. :) )<br /><br />Just be willing to let go of what was, and let those who have come run with it. Don't whine about it. Don't attack the newcomers. Just move on. If you miss the “good old days,” you can always start some new ones.<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com1tag:blogger.com,1999:blog-7017083405558956091.post-41708535545432778222010-08-30T10:26:00.000-07:002010-08-30T11:14:41.221-07:00GroovyMag Plugin Corner: JavaScript Validation Plugin<em>The following post is a reprint of the Plugin Corner article for the April 2009 issue of GroovyMag. You can find this and other past issues at <a href="http://groovymag.com/">http://groovymag.com</a>.</em><br /><br />Grails provides powerful and easy-to-use constraint validation. With a few short lines in a simple DSL, you can ensure that required fields are filled in or that numeric field values are within a specified range. If you take advantage of Grails’ scaffolding, error reporting is also handled for you. The only catch is that it’s server-side only. If you want this type of validation without a round-trip to the server, you’re on your own — unless you use Peter Delahunty’s brand new <a href="http://grails.org/plugin/javascript-validator">JavaScript Validation plugin</a>.<br /><br />Peter released the Javascript Validation plugin earlier in March and then went right to work improving it. At the time of this writing it is at version 0.7 and is working quite well. Let’s see how easy it can be adding client side validation to our Grails applications. We’ll start by installing the plugin:<br /><pre class="brush:bash"><br />> grails install-plugin javascript-validation<br /></pre><br />We’ll need to make a couple changes to the views that we want validation on, but first let’s look at the domain class that we’ll be working with.<br /><pre class="brush:groovy"><span class="Apple-style-span" ><span class="Apple-style-span" style="font-size: 16px; white-space: normal;"><br /></span></span><code><br />class Book {<br /> String title<br /> String author<br /> Integer pages<br /> static constraints = {<br /> title(blank:false)<br /> author(blank:false)<br /> pages(range:10..1000) <br /> }<br />}<br /></code><br /></pre><br />This simple <code>Book</code> class (bet you never saw that in an article before) has three constraints. We will use the JavaScript Validation plugin to check those constraints without a trip to the server.<br /><br />Open <code>grails-app/views/book/create.gsp</code> and take a look at the <code><g:form></code> declaration. It should look something like this:<br /><pre class="brush:xml"><br /><code><br /><g:form action=”save” method=”post” ><br /></code><br /></pre><br />The Validation plugin requires that our form contain a <code>name</code> attribute and an <code>onSubmit</code> attribute that calls the <code>validateForm</code> JavaScript function. So, let’s modify our form declaration to look more like this:<br /><pre class="brush:xml"><br /><code><br /><g:form name=”bookCreate”<br /><br /> onsubmit=”return validateForm(this);”<br /><br /> action=”save” method=”post” ><br /></code><br /></pre><br />Finally, we need to add the following line to the <code><head></code> section of our page:<br /><pre class="brush:xml"><br /><code><br /><jv:generateValidation domain=”book” form=”bookCreate”/><br /></code><br /></pre><br />Here we’re just using the minimum required attributes for the <code><jv:generateValidation></code> tag. The <code>domain</code> attribute takes the domain class name, but with the first letter lowercase. The <code>form</code> attribute takes the same value that we assigned to the <code>name</code> attribute of our <code><g:form></code> tag. That’s all it takes to start using this plugin.<br /><br />Now if we go to create a new <code>Book</code> and leave out the author’s name for some dumb reason, we’ll see something like the screenshot in Figure 1.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDfo2Paq6ojbBvxvggjmWF6HXsS6ae_O-NAHuNCq4zjGiUJfmykVLqiKEicTQCtZsOPKKnaJsUWMdJsnFlZ0YahsWezYRwR_YaYulUFF_ypFC-ufT5NPHEUEAm5y5v6W-PaOmXnbUK8j0/s1600/img1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 171px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDfo2Paq6ojbBvxvggjmWF6HXsS6ae_O-NAHuNCq4zjGiUJfmykVLqiKEicTQCtZsOPKKnaJsUWMdJsnFlZ0YahsWezYRwR_YaYulUFF_ypFC-ufT5NPHEUEAm5y5v6W-PaOmXnbUK8j0/s200/img1.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5511266117448654450" /></a><br /><br />Not bad for a couple lines of code. That’s just the basics. The <code><jv:generateValidation></code> tag has ten more attributes that we can use to add more vigor and vim to our validations.<br /><br />There is support for both domain classes and command objects. Errors can be displayed in a JavaScript alert (as shown in Figure 1), which is the default, or they can be shown in a list placed in a page element of our choosing, or we can even create custom error handling.<br /><br />Currently only the following constraints are supported by the plugin:<br /><ul><br /><li><code>blank</code></li><br /><li><code>nullable</code></li><br /><li><code>email</code></li><br /><li><code>creditCard</code></li><br /><li><code>matches</code></li><br /><li><code>range</code></li><br /></ul><br />This list is considerably shorter than the list of constraints that Grails provides, but as we can see by the 6 updates since its creation a few weeks ago, this plugin is being actively enhanced, so I wouldn’t be surprised to see more constraints supported soon.<br /><br />Oh, and lest I forget, the Javascript Validation plugin works with Grails internationalization. So with a minor tweak to our <code>messages.properties</code> file, we can customize our error messages as shown in Figure 2.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf0g34IBA1yIGXKHzVVAwSkPtmgHDB3KEOmKL2zS0MQdp5q02QupZWix2N6dYoR9MgtsmSWKKTUYDejS3grab8ePk3UiyAzUa6fYSPTKFdJjapEznqhXzT4I5_-4-RKLwDwUJeDn9oHzs/s1600/img2.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 175px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf0g34IBA1yIGXKHzVVAwSkPtmgHDB3KEOmKL2zS0MQdp5q02QupZWix2N6dYoR9MgtsmSWKKTUYDejS3grab8ePk3UiyAzUa6fYSPTKFdJjapEznqhXzT4I5_-4-RKLwDwUJeDn9oHzs/s200/img2.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5511266296743849266" /></a><br /><br />This plugin has great potential. It will already save significant development time in setting up client-side validation, and I’m sure it’s going to keep getting better. Stop by the Grails Plugin Portal and check it out. You can leave a comment with enhancement suggestions, or, if you’ve tried it out, let others know what you think with a rating. I’m giving it 5 stars!<br /><br /><h2>Resources</h2><br /><br />Grails Plugin Portal page:<br /><a href="http://grails.org/plugin/javascript-validator">http://grails.org/plugin/javascript-validator</a><br /><br />Peter Delahunty’s Blog:<br /><a href="http://blog.peterdelahunty.com/">http://blog.peterdelahunty.com</a><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-51880120088772478492010-06-15T10:17:00.000-07:002010-06-15T10:47:23.043-07:00ÜberConf - Exceeding ExpectationsÜberConf kicked off yesterday with the pre-conference iPhone/iPad workshop. The workshop was completely full, with just over 90 people. The view from the front of the room was pretty impressive -- all those glowing apples. ;-)<br /><br />Later, the conference proper got going with a great dinner and a keynote by industry luminary Cliff Click. At the time when a normal No Fluff, Just Stuff event would wrap up for the day, there was an opening reception with more food and drinks and a roving magician. A great time was had by all.<br /><br />This morning, the sessions are going in full swing. I'm actually skipping one right now to finish up my sample project for the Grails workshop tomorrow. But the rest of the week is packed with great technical sessions, and not a marketing person in sight!<br /><br />I caught Keith Donald's Spring MVC session this morning and plan on making it to a session by Ted Neward this afternoon. The content choices are amazing. You've got Java Collections, Functional Java, Groovy, Grails, Wicket, Camel, Hadoop, NoSQL, Agile Architecture, JRuby, TDD, and on and on. In fact, it's hard to think of a buzz word in the Java ecosystem that isn't covered here.<br /><br />And the attendees are the best part. I've met folks from all over the country and beyond. I even ran into members of CapJUG and the <a href="http://www.meetup.com/GatewayGroovyUsers/">Gateway Groovy Users</a>. Seeing so many old friends and meeting so many new ones is definitely the best part of a conference like this. And with the longer breaks, receptions, etc., you actually get time to visit with folks without missing the tech sessions.<br /><br />With all due respect to the many great folks who make the pilgrimage to San Francisco every year, this is what JavaOne should have been.<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-13518959992563588452010-05-12T03:34:00.000-07:002010-05-12T03:47:44.495-07:00Recording of Grails / Terracotta webinarIn case you missed it and in case you're interested, Terracotta has posted a recording of the webinar that Mike Allen and I held a couple weeks ago. You can catch it in all of its glory (or lack thereof :) at <a href="http://bit.ly/scaling_grails">http://bit.ly/scaling_grails</a>. <br /><br />During the demo I mentioned a blog post coming to the <a href="http://gquick.blogspot.com">GQuick blog</a> where we would add <a href="http://www.quartz-scheduler.org/">Quartz scheduling</a> to TekDays (the sample app from <a href="http://tinyurl.com/grails-quick-start">GQuick</a>), well that post ended up <a href="http://dave-klein.blogspot.com/2010/05/quartz-and-grails.html">here</a> instead. <br /><br />Once again I'd like to thank the folks at <a href="http://terracotta.org/">Terracotta</a> for their cool technology and for their support of the Grails community.<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-35273616825155126742010-05-04T13:33:00.001-07:002010-05-04T13:34:02.333-07:00Quartz and Grails: A Quick-Start Guide<p>Terracotta's Quartz scheduler has always played a key role in Grails development. Originally it was built into the framework; now it is a core plugin. Quartz allows us to have code executed at regular intervals. This a great way to have batch processes or system checks performed at off hours.</p><br /><p>The Quartz plugin provides three different mechanisms (triggers) to determine the timing of job execution: Simple, Cron, and Custom. With a simple trigger, we can set the amount of time to wait before initial job execution, an interval to wait between repeated executions, and the number of times the job should be executed. The cron trigger also allows us to set a start delay. Then it takes a cron expression, which we can use to set a wide range of schedules. With a custom trigger – well, you can use your imagination.</p><br /><p>In our TekDays application, we have lists of tasks that need to be done to organize a technical event. These tasks have due dates, but we currently have no way of reminding event organizers and volunteers when they have tasks that are overdue. That's where Quartz comes in. In this post, we'll create a Quartz job to check for overdue tasks and send a reminder email to the person assigned to that task.</p><br /><p>First, we'll install the Quartz plugin:</p><br /><pre class="brush:bash"><br />> grails install-plugin quartz<br /></pre><br /><p>The plugin provides us with a new Grails script, <span class="Apple-style-span" style="font-family:'courier new';">create-job</span>. We'll use this script to create our <span class="Apple-style-span" style="font-family:'courier new';">TaskReminderJob</span>.</p><p><br /></p><pre class="brush:bash"><br />> grails create-job TaskReminder<br /></pre><br /><p>The create-job script will create a stubbed out <span class="Apple-style-span" style="font-family:'courier new';">TaskReminderJob.groovy</span> that looks like this:<br /></p><br /><pre class="brush:groovy"><br />class TaskReminderJob {<br /> def timeout = 5000l // execute job once in 5 seconds<br /><br /> def execute() {<br /> // execute task<br /> }<br />}<br /></pre><br /><p>We'll replace the <span class="Apple-style-span" style="font-family:'courier new';">timeout</span> property with a triggers closure in a moment, but first let's look at the <span class="Apple-style-span" style="font-family:'courier new';">execute</span> method. This method will be called at the intervals that we determine with the triggers. We can put any code we want in this method, but the most common practice, and the one we'll follow, is to call a method of a service class.</p><br /><p>For triggering the call to our service method we'll use the <span class="Apple-style-span" style="font-family:'courier new';">cron</span> expression: <span class="Apple-style-span" style="font-family:'courier new';">"0 0 2 ? * MON-FRI"</span>, which will execute every weekday at 2:00AM. This is how our new <span class="Apple-style-span" style="font-family:'courier new';">TaskReminderJob</span> looks:</p><br /><pre class="brush:groovy"><br />class TaskReminderJob {<br /> def taskService<br /> static triggers = {<br /> cron name: 'cronTrigger', cronExpression: "0 0 2 ? * MON-FRI"<br /> }<br /><br /> def execute() {<br /> taskService.sendTaskReminders()<br /> log.info("Task reminders sent on ${new Date()}")<br /> }<br />}<br /></pre><br /><p>Now we need to add the <span class="Apple-style-span" style="font-family:'courier new';">sendTaskReminders()</span> method to our <span class="Apple-style-span" style="font-family:'courier new';">TaskService</span>. This method will use the Mail plugin (which you can find more about at <a href="http://grails.org/plugin/mail/">http://grails.org/plugin/mail</a>), so we'll add that to <span class="Apple-style-span" style="font-family:'courier new';">TaskService</span> too. Something like this:</p><br /><pre class="brush:groovy"><br />class TaskService {<br /> def mailService<br /><br /> //...<br /><br /> def sendTaskReminders(){<br /> def tasks = Task.findAllByDueDateLessThan(new Date())<br /> tasks.each{task -><br /> def recipient<br /> if (task.assignedTo)<br /> recipient task.assignedTo.email<br /> else<br /> task.event.organizer.email<br /> <br /> mailService.sendMail {<br /> to recipient<br /> from "admin@tekdays.com"<br /> subject "Task Reminder"<br /> body """The following task is overdue:<br /> ${task.title}"""<br /> } <br /> }<br /> }<br />}<br /></pre><br /><p>That's all there is to it. We now have the confidence of knowing that event organizers and volunteers will be kept informed of the tasks they need to do. And based on the experience of some people I know who recently put on a tech conference, this is important.</p><br /><p>Now, something that in days past might have required us developers to climb tall mountains to make supplication to sysadmins wearing robes and conical hats has been made almost trivial by Quartz and the Quartz plugin. I, for one, am impressed and grateful. (I'm getting way too old for mountain climbing.)</p><br /><p>But wait (as they say) – there's more. As TekDays gets more and more traffic (which we know will happen with all the new and exciting technologies coming out these days), we will want to take advantage of the power of Terracotta and cluster our Quartz jobs. To do this, we just need to create the property file: <span class="Apple-style-span" style="font-family:'courier new';">grails-app/conf/quartz.properties.</span> Then enter the following values in this file:</p><br /><pre class="brush:groovy"><br />org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore<br />org.quartz.jobStore.tcConfigUrl = localhost:9510<br />org.quartz.scheduler.instanceName = TekDaysScheduler<br />org.quartz.scheduler.instanceId = AUTO<br />org.quartz.scheduler.jmx.export = true<br /></pre><br /><p>Finally, we'll copy <span class="Apple-style-span" style="font-family:'courier new';">quartz-terracotta-1.1.0.jar</span> in our <span class="Apple-style-span" style="font-family:'courier new';">lib</span> folder. The <span class="Apple-style-span" style="font-family:'courier new';">quartz-terracotta</span> jar comes in the Terracotta download, which can be found at <a href="http://www.terracotta.org/dl/oss-download-catalog">http://www.terracotta.org/dl/oss-download-catalog</a>.</p><br /><p>Now, if we've clustered our TekDays application as described in <a href="http://gquick.blogspot.com/2010/03/clustering-grails-app-with-terracotta.html">an earlier post</a>, our scheduled jobs will be spread out across all the nodes. Not too shabby.</p><br /><p>There is still some room for improvement in the Grails / Terracotta integration story, but I continue to be amazed at just how low the barrier of entry is to these powerful products.</p><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com4tag:blogger.com,1999:blog-7017083405558956091.post-31350673768783960672010-04-26T17:09:00.000-07:002010-04-27T04:18:13.538-07:00Like speaking at a conference in my bath robeOn April 27th at 11:00am Pacific time, Mike Allen and I will be holding a free webinar on clustering and scaling grails applications the easy way. A webinar is a cool thing. It's like a tech conference session where you can't see anybody. So, while you're sitting at your desk at work or at home or in a coffee shop, Mike will be in California somewhere and I'll be sitting in my basement office in St. Louis, quite possibly still in my pajamas. <br /><br />But that's not the important part. The important part is that we'll be talking about how easy it is to make a Grails application scalable. To demonstrate that we'll be using one of my favorite sample apps, TekDays from <a href="http://tinyurl.com/grails-quick-start">Grails: A Quick-Start Guide</a>. <br /><br />If you haven't already, go ahead and sign up at <a href="http://bit.ly/aeDQ3I">http://bit.ly/aeDQ3I</a>. The whole thing will be recorded and posted later. So, if you can't make it on the 27th or if 11am Pacific is the middle of the night for you, register anyway so you can be notified when the recording is available.<br /><br />If you can make it though, it would be great to have you. <br /><br />See you there (in a figurative sense),<br />Dave<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com2tag:blogger.com,1999:blog-7017083405558956091.post-19660060095391363192010-04-07T19:29:00.000-07:002010-04-08T11:27:28.602-07:00ÜberConfI am very excited about the upcoming <a href="http://uberconf.com/">ÜberConf</a> - June 14 - 17, Denver, CO. Even before I found out that I'd be speaking at it, I was planning to attend. I've been to a lot of conferences, and I think this is going to be the best one ever!<br /><br />I've been attending technical conferences for over 15 years. I've been to big ones and small ones, free ones and expensive ones. Just doing a quick count in my head, I think I've been to around 35 tech events. Most of these have been as an attendee and on my own dime, because I am convinced of their usefulness and value. More recently I've been speaking at some conferences. Over the years I've become somewhat of a tech conference connoisseur. <br /><br />Of all these events, the best have been the ones put on by Jay Zimmerman of <a href="http://nofluffjuststuff.com/">No Fluff, Just Stuff</a> fame. The NFJS events and others, such as the Groovy/Grails Experience, the Agile IT Experience and SpringOne/2GX, have some elements that other conference organizers just can't seem to duplicate. <a href="http://codemash.org/">CodeMash</a> comes close, and the old Borland Developer Conferences were also pretty good, but neither of these are quite up to the level of an NFJS event. <br /><br />JavaOne used to score real high on the technical content before it became JavaFX One, but the conference organization and overall experience was always lacking. The SD conferences usually had some big names that were worth the price of admission, but the rest of the sessions were hit and miss, and the mobs that were there just for the free expo floor made it so difficult to get to sessions that it often wasn't worth it.<br /><br />The NFJS events have speakers who are well known, though maybe not as famous as some of the SD headliners. More importantly, they know their stuff, and they have tons of experience in presenting it to others. And since the event size is purposely kept small, it's easy to get to the sessions of interest and easy to get time to talk with the speakers. The schedule is always arranged with plenty of break time for the hallway discussions and questions after the sessions. And all of the little details that we don't really notice but that provide for a much better learning experience are taken care of.<br /><br />But back to ÜberConf. This event will, I'm sure, have the quality experience and flawless execution common to all NFJS events, but with an expanded focus, expanded schedule and an amazing line-up of speakers (and me too :).<br /><br />ÜberConf's technical content will be what JavaOne should have been over the last couple years. It will fully embrace Java the platform, with sessions on Java, Groovy, JRuby, Clojure and Scala. ÜberConf goes beyond just the languages and draws from the rich diversity of open source communities that have found a home on the JVM, with <a href="http://grails.org/">Grails</a>, <a href="http://wicket.apache.org/">Wicket</a>, <a href="http://gradle.org/">Gradle</a>, <a href="http://maven.apache.org/">Maven</a>, <a href="http://gaelyk.appspot.com/">Gaelyk</a>, <a href="http://camel.apache.org/">Camel</a>, and more. And since what we're developing with is only part of the story, ÜberConf goes on to bring together some of most important ideas in agile processes from speakers such as <a href="http://www.estherderby.com/">Esther Derby</a>, <a href="http://www.jrothman.com/">Johanna Rothman</a>, <a href="http://www.devjam.com/">David Hussman</a>, <a href="http://www.michaelnygard.com/">Michael Nygard</a>, and others.<br /><br />With a mix of 90 minute sessions and 3 hour workshops, and eight concurrent tracks to choose from, ÜberConf will be packed with great content. With attendance capped at 500, it will be easy to get time to talk with speakers and other attendees - and getting to and from the sessions will be easy.<br /><br />I speak from experience when I say that you will leave this conference full of new ideas and inspiration. Check out <a href="http://uberconf.com/conference/denver/2010/06/schedule_at_a_glance">the schedule</a>. You'll find plenty of sessions that apply to your current work, but don't stop there. To get the most out of an event like this, you need to go to sessions about topics you know nothing about. You will be amazed at how much you can learn about what you are currently doing by learning about new tools and technologies.<br /><br />Check out <a href="http://uberconf.com/">the site</a> for details. There's much more than I've discussed here, including sessions on iPhone, iPad and Android development. For what's included, the full registration price is a steal, but if you register by Monday, April 12th, there's a big discount. So register now, or register later, but do register and attend this awesome conference. <br /><br />See you there!<div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0tag:blogger.com,1999:blog-7017083405558956091.post-69612098746052334422010-03-27T10:33:00.000-07:002010-03-27T10:51:39.510-07:00Hats Off to Terracotta<p style="margin-bottom: 0in">One of the advantages of Grails is the way that it gives us access to the wealth of proven frameworks in the Java ecosystem. There are Java frameworks and libraries to help with every aspect of application development you could imagine. For many applications, a major requirement that the Java world has worked out quite well is scalability. And when we think of Java and scalability we naturally think of <a href="http://terracotta.org/">Terracotta</a>.</p><p style="margin-bottom: 0in">Of all the open source libraries and frameworks available in the Java ecosystem, Terracotta is one of the most Grails-friendly. In fact, one of Terracotta's projects is built right into Grails (EhCache). Another is one of the most popular Grails plugins (Quartz). What's really cool is that as an organization, Terracotta sees the important role that Grails is playing the Java development space, and is actively working to make their products integrate better with Grails.</p><p style="margin-bottom: 0in">Recently, I undertook the task of trying this integration out with the sample app from my book, <a href="http://pragprog.com/titles/dkgrails/grails">Grails: A Quick-Start Guide</a>. Other than Quartz, I hadn't used any of their products before, so I was a bit intimidated, but I was pleasantly surprised with how easy it is. As with any tool, you can get into more advanced usages that may take more configuration and more work. But the basic integration was a snap!</p><p style="margin-bottom: 0in">I've put up <a href="http://gquick.blogspot.com/2010/03/clustering-grails-app-with-terracotta.html">the first of a series of blog posts</a> on the GQuick blog, detailing the steps needed to integrate Terracotta's Web Sessions Express clustering tool with the TekDays application from the book. Future posts will cover some of the other products in the Terracotta family.</p><p style="margin-bottom: 0in">If you're a Grails developer and haven't taken a look at Terracotta, check 'em out at <a href="http://terracotta.org/">http://terracotta.org</a>.</p><p style="margin-bottom: 0in">Also check out these resources by others in the Grails community who have discovered the synergy of Terracotta and Grails:</p><p style="margin-bottom: 0in"><a href="http://adhockery.blogspot.com/2010/02/full-page-caching-in-grails-with.html">http://adhockery.blogspot.com/2010/02/full-page-caching-in-grails-with.html</a></p> <p style="margin-bottom: 0in"><a href="http://burtbeckwith.com/blog/?p=244">http://burtbeckwith.com/blog/?p=244</a></p> <p style="margin-bottom: 0in"><a href="http://ehcache.org/documentation/grails.html">http://ehcache.org/documentation/grails.html</a></p> <p style="margin-bottom: 0in"><a href="http://adhockery.blogspot.com/2010/02/full-page-caching-in-grails-with.html">http://alterlabs.com/technologies/java/terracotta-plugin-for-grails/</a></p><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com2tag:blogger.com,1999:blog-7017083405558956091.post-48550415821509311772010-03-05T09:02:00.000-08:002010-03-05T09:37:53.482-08:00GroovyMag Plugin Corner: Grails Help-Balloon Plugin<em>The following post is a reprint of the Plugin Corner article for the January 2009 issue of GroovyMag. You can find this and other past issues at <a href="http://groovymag.com/">http://groovymag.com</a>.</em><br /><br />Sometimes our web applications get a little more complex and not entirely intuitive. When this happens, it is important to find ways to provide the cues and clues that our users need to find their way around and to accomplish the task at hand. The Help-Balloon plugin can help with that.<br /><br />The Help-Balloon plugin provides a pair of tags which will render an icon in your view. This icon is a link which brings up a balloon shaped, non-modal dialog with the text that you give it. It’s simple, but very handy. Let’s see how we can add this helpful gadget to our toolbox.<br /><br />First things first. Make sure that you are in your project’s root directory, and then run the following command:<br /><br /><pre class="brush:bash"><br />grails install-plugin Help-Balloon<br /></pre><br /><br />The next step is to add the <code><g:helpBalloon></code> tag to the head of our <code>.gsp</code> page. For our example we will start with our List view. Here’s the head section of our <code>list.gsp</code>:<br /><br /><pre class="brush:xml"><br /><code><br /><head><br /><br /><meta http-equiv="Content-Type"<br /><br />content="text/html; charset=UTF-8"/><br /><br /><meta name="layout" content="main" /><br /><br /><g:helpBalloons /><br /><br /><title>Book List</title><br /><br /></head><br /></code><br /></pre><br /><br />The <code><g:helpBalloon></code> tag will load the Prototype Javascript library (if it isn’t already loaded). By default it will find this library in your Grails installation. If you have a different location for Prototype, you can declare that with the base attribute. We’ll take a look at some other customizations that are possible with this tag shortly. For now, let’s add a help balloon to our list view.<br /><br />In our <code>list.gsp</code> we will add another <code><td></code> to our table. If all goes well, this will give us an icon at the end of each row in our list table.<br /><br /><pre class="brush:xml"><br /><code><br /><td><br /><br /><g:helpBalloon title="Book Info"<br /><br />content="${bookInstance.moreInfo()}"/><br /><br /></td><br /><br /></tr><br /></code><br /></pre><br /><br />As you can see, the <code><g:helpBalloon></code> tag has <code>title</code> and <code>content</code> attributes. The <code>title</code> will show up as a heading in the balloon and you can probably guess what the <code>content</code> ends up as. For static<br />text from a message bundle, you can also use the <code>code</code> attribute. In our example the balloon content will be the same as the fields in the table but in a paragraph format. The content can be HTML so <code><br /></code> tags are an easy way to structure the text for our balloon, but if we put them in the tag it doesn’t work. For example:<br /><br /><pre class="brush:xml"><br /><code><br /><g:helpBallon title="Foo" content="line1<br/<br /><br />>line2<br/>line3" /><br /></code><br /></pre><br /><br />will leave the content of the balloon empty. (At least that’s what happened to me.) However those same break tags passed in as the result of a method work fine. So, we added a <code>moreInfo()</code> method to our <code>Book</code> class to give us the text we want. This has a nice side-effect of keeping our page cleaner.<br /><br />For the curious here’s the code for the <code>moreInfo()</code> method:<br /><br /><pre class="brush:groovy"><br />String moreInfo(){<br /> """$title <br/><br /> by $author<br/><br /> published in $published<br/><br /> pg: $pages / ISBN: $isbn """<br />}<br /></pre><br /><br />When we run our application we get something like this:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxREdgpxeV_tKcBjNrpYnf2akVqC-pc86u7VYzjhe4yxXlPrrokobes7QMhGuUVmpEy0StnQ5Us3wrtgTUWtemxREKOK9COv5HK-Xyrc9ej-lNxIODTc1t4jZ4mQdOg32jw3ihRtRwV3c/s1600-h/help-book-list.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 84px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxREdgpxeV_tKcBjNrpYnf2akVqC-pc86u7VYzjhe4yxXlPrrokobes7QMhGuUVmpEy0StnQ5Us3wrtgTUWtemxREKOK9COv5HK-Xyrc9ej-lNxIODTc1t4jZ4mQdOg32jw3ihRtRwV3c/s200/help-book-list.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5445204942697634514" /></a><br /><br />And when we click on one of those icons, the balloon will show<br />up:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6_Ow6-QXGi9Ake4rgIqQTp0OPfeE5IvdDgwS0-9VHQdlW-uwWdUKsb3SH9RjpWAiWxffXsVsWLfpG3gCp4HyLaGy4Kkk5CpTZ4pGqIhQAMHkScK_P3gcy3lg2A9ZegRbpMih5v1CPASw/s1600-h/help-balloon.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 154px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6_Ow6-QXGi9Ake4rgIqQTp0OPfeE5IvdDgwS0-9VHQdlW-uwWdUKsb3SH9RjpWAiWxffXsVsWLfpG3gCp4HyLaGy4Kkk5CpTZ4pGqIhQAMHkScK_P3gcy3lg2A9ZegRbpMih5v1CPASw/s200/help-balloon.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5445205160700394082" /></a><br /><br />That’s about all there is to using the Help-Balloon plugin - except that I promised to show how we can customize a couple more things with the <code><g:helpBalloon></code> tag that goes in the <code><head></code> of our page. This tag <strong>can has</strong> optional <code>button</code> and <code>icon</code> attributes (it can has cheezburgr, too). <em>[After seeing this typo, I couldn't resist. -- Ed.]</em> Both of these take a path to an image. If you specify an icon it will replace the "letter i" icon that is used for the link. The button attribute is used to replace the "x" in the upper right corner of the balloon.<br /><br />The Help-Balloon plugin is based on the HelpBalloon system written by Beau Scott. You can find more detailed documentation and keep up with the latest updates of the Javascript code on his<br />site (see references).<br /><br />There you have it: a Grails-easy way to add help balloons to your applications. I bet you can think of dozens of ways to use help balloons. Well, at least two or three. In any case, your toolbox just got a little more powerful.<br /><br /><strong>Resources</strong><br />Help-Balloon Plugin page:<br /><a href="http://grails.org/plugin/help-balloons"><br />http://grails.org/plugin/help-balloons<br /></a><br />Beau Scott’s web site:<br /><a href="http://www.beauscott.com/"><br />http://www.beauscott.com/<br /></a><div class="blogger-post-footer"><p>
These cobblestones were kicked down by <a href="http://dave-klein.blogspot.com/">Dave Klein</a>.
</p></div>Dave Kleinhttp://www.blogger.com/profile/05996044798024907436noreply@blogger.com0