Category Archives: Clojure

Java Does Not Need Closures. Not at All.

I hope that most Java developers are aware of the Swing threading policy. It makes sense, except for that it’s so insanely hard to follow. And if you do follow it, I dare say there is no place with more ridiculous boilerplate.

Here’s two examples that recently got me scratching my head, gnashing my teeth, and eventually weep in disdain.

Case One: Display Download Progress

class Downloader {
    download() {
        progress.startDownload();
        while(hasMoreChunks()) {
            downloadChunk();
            progress.downloadedBytes(n);
        }
        progress.finishDownload();
    }
}

class ProgressDisplay extends JPanel {
    JLabel label;
    startDownload() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                label.setText("Download started");
            }
        });
    }
    downloadedBytes(int n) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                label.setText("Downloaded bytes: " + n);
            }
        });
    }
    finishDownload() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                label.setText("Download finished");
            }
        });
    }
}

Solution? Easy! Just write your own JLabel wrapper to hide this mess. Then a lengthy JTable utility. Then a JProgressBar wrapper. Then…

Case Two: Persist Component State

Task: Save JTable state to disk. You’ve got to read table state in EDT, but writing to disk from EDT is not the the best idea.

Solution:

ExecutorService executor = Executors.newSingleThreadExecutor();

void saveState(final Table table) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            TableColumns state = dumpState(table);
            executor.execute(new Runnable() {
                public void run() {
                    saveToDisk(table.getTableKey(), state);
                }
            });
        }
    });
}

Two inner classes, inheritance, all those publics and voids and parentheses. And there is no way to avoid that!

In a sane language, it could look like:

(defn save-state [table]
  (do-swing
    (let [state (dump-state table)]
      (future (save-to-disk table state)))))

All semantics. Little ceremony, almost no syntax. If you counted characters in both solutions, I guess the entire second snippet is as long as the first one somewhere to the invocation of invokeLater. Before you get to the actual logic. No strings attached, do-swing and future are provided by the language or “official” utils.

Bottom Line

I recently saw two presentations by Venkat Subramaniam on polyglot programming where he mercilessly made fun of Java. In his (vaguely remembered) words, when you write such code for the whole day, you come back home and weep. You can’t sleep because you’re tormented by the thought of the abomination you created, and that you will have to deal with tomorrow. If your children asked you what do you for living, would like them to see this?

Yaclot 0.1.2: Extended Date Conversions

I released a new version of my Clojure conversion and map transformation library to Clojars. It includes two new features:

1. Added natural conversion between Long and Date.

2. You can pass a collection of formats for converting String to Date. It attempts parsing with each of the formats and returns first result which didn’t throw ParseException.

(convert
  "2/12/11"
  (using-format ["yyyy-MM-dd" "M/dd/yy"]
    (to-type java.util.Date)))
; => #<Date Sat Feb 12 00:00:00 CET 2011>

Enjoy!

What I Got from 33rd Degree

This week I attended the 33rd Degree conference in Kraków. Most of the time I followed the “soft” path and learned how people work and how I can improve my skills (not only as a programmer, as it turned out). Here’s a quick summary of some of the valuable stuff I got there. It’s going to be fairly shallow, but anyway there is no way I could describe 25 hours of talks from very smart guys in a single blog post.

Tunnel Vision

Like all people, developers tend to get tunnel vision. When you’re in the flow, you don’t care about the big picture. You just crank out code and your thoughts are faster than your fingers. The more you focus on detail, the more you’re biased and suffer from inattentional blindness. Vision, scope and quality fade to background. That’s not good, because you’re a part of a bigger machine whose basic purpose is delivering business value.

Paweł Lipiński did a great job explaining how various agile tools address it. User stories clearly state what business value you’re about to deliver. Programming in pairs prevents individuals from getting out of control by having one programmer paying more attention to the strategic vision. Finally, several layers of tests (including acceptance tests) verify that the specification is met even as the code is refactored or extended.

Marcin Kokott and Martin Chmelar tackled it from a broader perspective. Sometimes companies realize something is wrong. They’re not going fast enough, or what they deliver does not exactly meet business expectations. So they hire consultants like these guys who talk to all involved parties (from developers to executives) and investigate how the whole process works. What happens from the moment a feature is described to when it actually is implemented. Sometimes the problem is not in developers, but on a higher level of the whole process. For instance, marketing or stakeholders generate so much pressure on developers that they produce poor code and don’t meet expectations. That leads to more pressure and demotivation of developers… and so we get a negative reinforcement loop that leads to inevitable failure.

Another topic that the two Martins touched is how experience adds walls around you. You get used to some way of thinking and get less and less creative. You no longer try and think outside of the box. You become prejudiced and make pessimistic assumptions. In his final “Abstraction Distractions” key note Neal Ford followed it by stating that what shields you from the world at some point can become a prison later. We think of file systems, while our users only care about documents. They want to move pictures from the camera into the app – not think about folders, JPGs, mounting an external storage or whatever (example from my experience). We are used to so many abstractions. It’s interesting how it took 30 years to market user interface that has no file system, no mouse and keyboard (that is the iPad). It took quite a while to make the breakthrough.

Finally, Matt McCullough made an interesting point. In both his talks on Git and Hadoop he stressed how you should always try and understand your tools on one level below what you need right now. It not only helps you understand the thing better, but there may be some very interesting and worthwhile piece of engineering underneath you can learn from. Oh, and in just one hour Matt managed to explain how Git works and make me actually want to give it a shot. Something that many other advocates could not make me do.

Sharpening the Axe

Another recurring topic was self-improvement. First of all, why should we care? Why not just hold on to your knowledge of the good old Java as of 2005? Quick answer: To keep your job. Longer answer: Because that’s professional. Constant self-improvement is part of the job. If you don’t do it, you will be unable meet new requirements. Web development? Fancy Ajaxy UIs? Scalability? Big Data? Standard requirements today, hard if not impossible to solve with the technology and knowledge as of 5 or 10 years ago. In fact, you even may want to learn out of boredom! But how?

There is no way to describe what Venkart Subramaniam and Ted Neward have done. Not only they had a lot of great thought-provoking content to present, but they are fantastic speakers (true rock stars in the old good rock’n’roll sense). Their frantic enthusiasm and passion were truly contagious. Venkart compared learning to mental exercise that you do to stay energized and in shape. To get the most out of it, you should learn something completely different from what you know. No point learning C# when you’re a Java master. Go learn Clojure or Erlang – something that hurts when you first do it! Even if you don’t use it directly, it may change the way you think in your primary environment (that’s what I loved in learning Clojure). Another nice side effect is that the more you know, the less effort it takes to learn another new thing (because you just learn the deltas).

On the other hand, Ted stressed the fact that there’s always a wide range of tools to choose from. There’s no silver bullet to be found. Some tools work here, some over there. You may or may not need JEE. Or Rails. Or Hibernate. Or blub. You can’t blindly apply whatever your current favorite toy is. Be critical. Even worse, you can’t rely on authorities or community to tell what’s the best. There’s no such thing as universal “best practices”. Everything depends on context.

Productivity

Finally, I really enjoyed two talks on productivity by Nate Schutta and Neal Ford.

It all started with Grzegorz Duda urging participants not to tweet about the conference (his conference!), but focus on the real people and stuff around them. Not too long after that Nate gave a great talk about the broader context of productivity. First of all, to be productive you have to be physically healthy. If you sacrifice sleep or physical exercise, your productivity actually goes down due to fatigue, poor blood flow etc. Another side of the same coin: Time and attention are limited. You only have so much time. There’s no way you can experience, enjoy and learn everything. You have to be very picky about everything you do. Are Twitter, Angry Birds or TV really worth it? Go on an information diet and be selective about everything you pick up. Drive towards doing fewer carefully chosen things in much more depth.

Compared to this, Neal’s talk was very down to earth. He shared many tricks that can make you a more productive programmer on a daily basis. Go faster by using keyboard and shortcuts of all kinds for everything, because typing is a lot faster than navigation. Mouse is for your grandmother. Stop repeating yourself and automate everything. Stay focused by getting a more comfortable environment – comfortable chair, dual monitors, virtual desktops, full screen applications, and so on. Avoid duplication by having one canonical representation of everything. If you need to update docs to keep rest of the team up to date, maybe you can generate an RSS feed for them from the VCS commit log? Finally, automate everything. Use one-step build, continuous integration and automatic tests. Don’t force yourself to interact with what you’re building – use a test suite such as Selenium to do it for you, and run it repeatedly as often as you need. Make your QA record their steps in Selenium so that you can easily and accurately replay it.

Be a craftsman, not a laborer. Build your own tools if you need.

Driving Change

One recurring question common for many different topics was: That’s all cool stuff, but how do you drive the change? How can you do it in your company? How to change yourself? The same question applies to developers’ observations on problems in the whole process (supposedly beyond their responsibility), but also to introducing new technical solutions (languages, techniques, libraries) in development itself. Even to self-improvement outside software development.

If you’re lucky, you may be in a team like the one Jakub Nabrdalik described. A bunch of people who want to improve their skills and company themselves and have enough determination to convince the boss to do it in their paid work hours. For example, it could be weekly workshops, presentations or team code review. More on that here

That’s great if you’re in a professional and energized team with an understanding boss. If you aren’t that lucky, you may still be able to sneak some stuff in. Clojure community has heard of the anecdotal way to introduce their favorite toy: Don’t call it a language. Java is a language. That’s a Huge Deal. Don’t do it, just call it a concurrency library for Java. Another example (thanks Artur): Use Gradle to solve a tricky build problem that would take 1000 lines of Ant… and open a back door for Groovy.

Venkart Subramaniam used a great metaphor. Imagine an elephant rider. Of course when the elephant takes control, it will ride wherever it wants. It won’t go somewhere only because the rider frantically says so. But if the rider is smart and rational, he may be able to control the elephant. That elephant can be your environment, or your inner lazy, prejudiced and emotional self.

Last but not the least, be a child. Drop your assumptions and prejudice. Just try it – it may simply work!

Next Year

This lengthy post may not even cover a half what I was able to see at the conference. It merely scratches the surface and does not give even a slightest hint at the great atmosphere there. Grzegorz Duda made an excellent job in organizing the event and gathering so many talented speakers. I already am looking forward to the next year. If this was only the first edition, the next one can be an earthquake. The preparations have already begun and with such stars as Uncle Bob on board it just can’t go wrong.

“Processing in Clojure” Made Functional

Invited to nitpicking by Jacek Laskowski in his latest post titled Processing in Clojure, I decided to write my own version of his flower-drawing application. I find it an interesting challenge and illustration for my previous post about functional thinking and the use of language and decomposition.

Full source code is below, but let’s start with what I did not like and decided to rewrite.

I find Jacek’s code rather structural and hard to comprehend. Everything happens in one big function and it takes quite a while to understand what it does and how. It’s hard to see why angle is an angle, and variables called a and value don’t make it any easier.

Thus my first two improvements are: Break it down into smaller pieces and use more informative names. For instance, value is in fact scale. I extracted drawing flower to a separate function with clear distinction to drawing petals and the central piece. I also paid more attention to variable names and hid the more complex concepts behind simple, well-named functions.

The second type of improvements is use of functional features. After a while of careful inspection I observed that angle is a simple linear sequence, and scale is result of a simple function on this sequence. I decided to replace it with a dedicated infinite sequence.

In the end, this code is longer and has more levels of abstraction, but I think it’s more functional and comprehensible. Functions are much shorter. Details no longer obscure the view, but are hidden behind more descriptive names. Now you can actually see that the applet’s draw draws a flower which consists of petals and the central piece. The central piece is a simple circle, while petals are several circles of random size and color around the center. Then only if you want you can delve into details of how their color and size are generated.

Like I mentioned in the first paragraph, I find it a nice illustration of what Paul Graham describes as building a language for the solution.

Two Worlds: Functional Thinking after OO

It goes without saying that functional programming is very different from object-oriented. While it may take a while to grasp, it turns out that functional programming can also lead to simpler, more robust, maintainable and testable solutions.

The First Encounter

In his classic “Clean Code” Robert C. Martin describes a great (and widely adopted) way to object oriented programming. He says code should read from top to bottom like prose. Start with the most high-level concepts and break them down into lower-level pieces. Then when you work with such a source file, you may be able to more easily follow the flow and understand how it works.

It occurred to me it’s quite different from how the natural flow of functional programming in Clojure, where typically all users are below their dependencies. I was unsure if (and how) Uncle Bob’s ideas apply on this ground. When I tweeted my doubts, his answer was: “You can forward declare”. I can, but still I was not convinced.

The light dawned when I came across Paul Graham’s essay titled “Programming Bottom-Up”. The way to go in functional programming is bottom-up, not just top-down.

Language for the Problem

Lisp (and Clojure) have minimal syntax. Not much more than parenthesis. When you look at Clojure source, it’s really dense because there is no syntax obscuring the flow. What you can see at the bottom of the file, though, appears to be program in language created just for this problem.

As Paul writes, “you don’t just write your program down toward the language, you also build the language up toward your program. As you’re writing a program you may think +I wish Lisp had such-and-such an operator.+ So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on.”

Simplicity and Abstractness

Ending up with a language tailored for the problem is not the only nice feature of functional programming. Compared to object-oriented, functional code tends to be a lot more abstract. There are no intricate nets of heavy stateful objects that very often can’t talk to each other without adaptation and need a lot of care to weave together.

Data structures are very simple (if not minimalistic), what makes them easy to use with more functions. They also are immutable, so there is no risk of unexpected side effects. On the other hand, because of simplicity of data structures functions turn out to be much more abstract and generic, and hence applicable in broader context. Add closures and higher-order functions and get a very powerful engine with unlimited applications. Think how much you can do with map alone – and why.

Another way to look at code organization is layers or levels of abstraction. In object-oriented, it usually means that a bottom layer consists of objects which provide some functionality to the higher level. Functional programming takes it one step further: “[each layer acts] as a sort of programming language for the one above.” And if there is a need for distinction to layers, it’s only because of levels of abstraction. Much rarelier because of incompatibility and never because of handcuffing encapsulation.

Maintainability and Code Organization

We all know that in object-oriented programming most of the time you should start with the purpose at hand and go for a very concrete, specialized design. “Use before reuse” is the phrase term here. Then, when you need more flexibility you decompose and make the code more abstract. Sometimes it can be a difficult, time-consuming and bug-inducing effort. It’s not the case with functional programming. “Working bottom-up is also the best way to get reusable software. The essence of writing reusable software is to separate the general from the specific, and bottom-up programming inherently creates such a separation.”

Compared to OO, refactoring of functional code is trivial. There is no state, dependencies or interactions to worry about. No way to induce unexpected side effects. Each function is a simple construct with well-defined outcome given the direct input. Thanks to that, it’s also much easier to test (and cover with automated test suites).

The Curse of Structured Programming

Object-oriented originated from structured programming and all developers inevitably have such background. It takes some training to learn how not to write 2,000-line classes and 500-line methods. It takes much more to learn how to avoid inheritance, program to an interface, compose your code of smaller units and cover them (and their interactions) with tests.

There are ways to make object-oriented programs more likely to succeed, have fewer bugs and be more maintainable. A ton of books has been written on this, including but not limited to excellent and invaluable works by Robert C. Martin, Martin Fowler, Eric Evans, and so on, and so forth. That’s a lot of prose! It turns out that object-oriented programming actually is very difficult and needs a lot craftsmanship and attention.

Functional programming is free from many of these issues. What’s more, learning it yields great return to an object-oriented programmer. It can teach you a lot about algebraic thinking, but also breaking code down into smaller pieces, intention-revealing names and interfaces, avoiding side effects and probably many other aspects.

Yaclot 0.1.0 Released (Clojure Conversion and Record Transformation Library)

I released Yaclot 0.1.0 to Clojars. This version can be used to convert single values as well as records.

Converting individual values looks like:

(convert "2011-02-12" (to-type java.util.Date))
; => #<Date Sat Feb 12 00:00:00 CET 2011>

(convert "2/12/11"
    (using-format "M/dd/yy" (to-type java.util.Date)))
; => #<Date Sat Feb 12 00:00:00 CET 2011>

(convert 5000.42 (to-type String (using-format "%,.2f")))
; => "5,000.42"

Order of using-format and to-type doesn’t matter. using-format is optional (default for dates is yyyy-MM-dd).

You can also use it to convert records in a single operation:

(map-convert 
  {:dt "2011-02-12" :int 42 :label "Label"}    ; Record
  {:dt  (to-type java.util.Date)               ; Desired types
   :int (to-type String)})
; => {:dt #<Date Sat Feb 12 00:00:00 CET 2011>, :int "42", :label "Label"}

The project originated from a pet web application, where I needed to deal with parsing and formatting numbers and dates between the “presentation”, “business logic” and “database” layers.

To learn more about motivation, features and syntax, take a look at the draft in my previous post.

This version supports conversions between String, Date and numeric types. Next on the road map is exception-free error handling with local bindings and validation.

See also:

Designing Yaclot: Generic Clojure Conversion Library

In real Clojure applications you often cannot avoid explicit type conversions, even though the language does not require you to explicitly specify types all the time. Another great feature of Clojure is its universal data structure: most of the time you don’t need anything more than a simple map or record. However, these records often need to be a bit different in different areas of the applications.

Rationale

Examples? You may have a java.sql.Date in database and backend, but your web front end provides you with a String. Or your backend uses rational numbers, but you need to format them into nice Strings for presentation.

Sometimes you operate on whole records. From database you may pull the following:

(def db-sample
  {:date    2011-02-01 ; java.sql.Date
   :balance 2042.00    ; java.math.BigDecimal
   :credit  1000.00    ; java.math.BigDecimal
   :roi     2.13 })    ; java.math.BigDecimal

… for display you would like to use:

(def presentation-sample
  {:date    "Feb 1, 2011" ; String
   :balance "$2,042.00"   ; String
   :credit  "$1,000.00"   ; String
   :roi     "2.13%" })    ; String

… and you need to support input from a web form as:

(def form-sample
  {:date    "2011-02-01"  ; String
   :balance "2042"        ; String
   :credit  "1000"        ; String
   :roi     nil })        ; Rational calculated 
                          ; by back-end from other fields

All three have very similar structure, but implementing all these transformations can be pain.

Planned API for generic converter

I am implementing a library that will do it for you, with API similar to the following:

(def db-fmt
  {:date    (to-type java.sql.Date)
   :balance (to-type java.math.BigDecimal)
   :credit  (to-type java.math.BigDecimal)
   :roi     (to-type java.math.BigDecimal) })

(def presentation-fmt
  {:date    (using-format "MMM d, yyyy" (to-type String))
   :balance (using-format "$%.2f"       (to-type String))
   :credit  (using-format "$%.2f"       (to-type String))
   :roi     (using-format "%.2f%%"      (to-type String)) })

(def form-fmt
  {:date    (using-format "yyyy-M-d" (to-type java.sql.Date))
   :balance                          (to-type java.math.BigDecimal)
   :credit                           (to-type java.math.BigDecimal) })

(map-convert db-sample presentation-fmt)
=> ; (similar to presentation-sample)

(map-convert form-sample db-fmt)
=> ; (similar to db-sample)

Another feature is generic conversion function for individual values:

(convert "2011-02-12" (to-type java.util.Date))
; => #&lt;Date Sat Feb 12 00:00:00 CET 2011&gt;

(convert (java.util.Date. 111 1 12) (to-type String))
; => "2011-02-12"

(convert 42 (to-type String))
; => "42"

(convert "2/12/11" (using-format "M/dd/yy" (to-type java.util.Date)))
; => #&lt;Date Sat Feb 12 00:00:00 CET 2011&gt;

Ideas for the Future

In the future, this library could support pre- and post-conversion validation. For instance, check that balance is not empty and date is in the correct format before conversion, and validate that balance and credit are positive once they are numbers.

Another idea is using it as a base for yet another HTML form manipulation library. I found existing libraries somewhat disappointing as they imposed to many restrictions on me. I would like to have the ability to manipulate and lay out forms as I please, and only use the bits of the library that I need right now.

Current Status

Currently much of the API and features are designed, but only the above presented part is implemented (not even supporting formats for numbers, only for dates). Once I implement conversions between all popular/basic types I will mark it 0.1 and push to Clojars. Error handling and validation are next on the road map.

The code is available at github.

Feel free to share any comments or ideas.

TDD in Clojure: Mocking & Stubbing

A few minutes into my first real TDD trip in Clojure I discovered there is two reasonable ways I can do tests: Mocking or black-box testing. I decided to go for mocking, and so I discovered clojure.contrib.mock. I found the docs fairly confusing, but finally understood it with a little help of this article and research.

Verify Calls to a Function

Assuming we have a function to compute square of a number, we want to write another function for square of sum.

(defn square [x] (* x x))

Our test can look like this:

(ns squirrel.test.core
  (:use [[clojure.test]])
  (:use [[clojure.contrib.mock]]))

(deftest test-square-of-sum
  (expect [square (has-args [3])]
    (square-of-sum 2 1)))

This use of expect asserts that when we execute the inner form (square-of-sum 2 1), it calls square with argument equal 3. However, it does not execute square itself. The only thing that this test checks is whether square got called. In particular, it does not check what (square-of-sum 2 1) returns. We’ll get back to stubbing in a moment.

Stubbing

Let’s modify our test to also assert the final result:

(deftest test-square-of-sum
  (expect [square (has-args [3])]
    (is (= 9 (square-of-sum 2 1))))

When the test runs, it fails because square-of-sum returns nil. The reason is that expect replaces square with a stub which by default doesn’t return anything.

To have stub return a concrete value, we can use the returns function:

(deftest test-square-of-sum
  (expect [square (returns 9 (has-args [3]))]
    (is (= 9 (square-of-sum 2 1))))

Voila. Now the test passes.

To recap, what this two-line test does is:

  • Create a stub for square which returns 9 for argument of 3.
  • Assert this stub is called with argument 3.
  • Assert that square-of-sum calls this stub with argument 3.
  • Assert that square-of-sum eventually returns the correct value.

Quite a lot for such a tiny test.

Expectation Hash

You may be wondering what exactly the second argument in each binding pair is. Clojure docs call it expectation hash.

Each function that operates on an expectation hash, such as has-args or returns, has two overloaded versions. One of them only takes a value or predicate and returns a new expectation hash. Examples include (returns 9) or (has-args [3]).

The other version takes an expectation hash as the second argument. These versions are used to pass the expectation hash through a chain of decorators. Order of decoration does not matter, so (returns 9 (has-args [3])) is effectively the same as (has-args [3] (returns 9)).

33rd Degree Conference

This April I’m going to attend the first eddition of the 33rd Degree Conference in Kraków. Not only does it have an exceptional theme (check out the web page!), but also has attracted several interesting speakers.

For some reason I am most interested in the non-Java talks and workshops given by Neal Ford (The Productive Programmer, Functional Thinking (hey, Clojure!) and Abstraction Distractions) and Linda Rising (Deception and Estimation). If there was a “Productivity and Psychology for Developers” conference, I would be the first to sign up for it.

Then there is a promising talk by Michael Nygard on scalability, as well as two sessions by Matthew McCullough on Git and Hadoop (both high on my to-learn list). Last but not least, a whole lot of more or less predictable talks on Java (mostly but not only EE).

I wish there was more Clojure and less Groovy on the schedule. Maybe next year. Anyway, the agenda is packed with interesting events and I expect it to be three very interesting and productive days.

Learn-Clojure.com: Clojure basics distilled

Kyle Cordes has put up a new site dedicated to Clojure: learn-clojure.com. As you can read in it’s FAQ, it is an attempt to consolidate just the most useful introductory material in one place, presented in a way that aims to help new or prospective Clojure developers.

At this moment that means basic information on what Clojure is, as well as many useful references to tutorials, videos and books. Clearly it’s not meant to compete with clojure.org or clojuredocs.org. Nor is it another tutorial or a garbled list of everything and nothing. It’s merely a clean, concise, nicely-organized gateway to the Clojure world.

This is very important, because while Clojure is rapidly gaining popularity (some are dubbing it “the next big thing” after OOP), it may be pretty discouraging at the beginning. In this world of enthusiastic magicians, crude immature frameworks and sparse documentation, by no means has finding my way been easy. Let alone answering the fundamental questions of “why?”, “what?” and “how?” That was an empty niche, and it’s great that Kyle made an effort and organized this together.

Unfortunately, apart from the Community section (not much going on in Poland) it does not provide much information to people who already are familiar with the basics. I’d love to see such a nice list on more concrete subjects like: “What are my options for building a web app?”, “How can I access the database?”, “How do I integrate it with JEE?” As well as a showcase of successful, inspiring (and mature) applications like Incanter or Ring. But that is yet to come, or may even be out of scope of this site.