She is a self-proclaimed language geek and sys- tems person. She gave up trying to make her mother understand what she does for a living. One feature common to both these approaches is the reliance on different application com- ponents interacting asynchronously. This asynchrony provides many benefits, including testing, scalability, and resilience.
However, the pat- terns used in constructing asynchronous applications are quite differ- ent and not as familiar to many developers. Continuations, long a part of the functional language community, are currently regaining popularity, primarily in web programming, al- though there is still a fair amount of controversy as to whether this is a good thing. This essay first introduces the idea of continuations and demonstrates their usefulness in various contexts. If you think about any program and some random point in the execution of that program for some input set, there are two clear sets—those instructions that have already happened and those instructions that are left to execute.
That second set is the continuation. One of the important aspects of this notion of a continuation is that, as pointed out in the Wikipedia definition, the continuation contains the context of the execution to that point. Effectively, the continuation is a closure that has a binding for the variable x. Another continuation exists after the assignment to y that has the context of variable bindings for both x and y.
Consider the following code for a recursive function, this time written in Scheme: define times lambda l if empty? This presents a recursive function that returns the product of a list of numbers. To clarify the syntax, lambda expressions define functions. In this case, I am naming the function times. The if has three subexpressions: the predicate, the true clause, and the false clause. The function returns the value 1 when the list is empty; otherwise, the return value is the product of the recursive call on the rest of the list and the first element in the list.
Now compiler writers will cringe and want to convert this recursive function into a loop to make it more efficient. There is a standard trans- lation to a form called continuation passing style that can in general be used to translate a recursive function into an iterative loop. The core of this translation is to establish what needs to happen after each of the recursive return statements.
In tail recursive form, no computa- tion is required on the return values; the final, innermost return value bubbles up to be the return value from the entire call stack. You could achieve a simple transformation as follows: define times lambda l cpsTimes l 1. This results in a tail recursive implementation. In this case, the analog to the continuation is the built-up, temporary result that is returned at the end. Those with experience in compiler optimization will note that there is a flaw here for floating-point arithmetic: the order of the multiplications is reversed.
One quick way to fix that is to simply change the first function to the following: define times lambda l cpsTimes reverse l 1. This results in the same order of multiplication. Another approach, which demonstrates a more sophisticated continuation, is as follows: define times lambda l cpsTimes l lambda x x. Here, the continuation created at each recursive call captures the com- putation that would have occurred in the original recursive function. At each level of the recursive call, you create a new continuation that captures the input continuation contained in the parameter and the value from the first element in the list at that level.
When the recursion bottoms out, the continuation is applied to the value 1, and the val- ues cascade through the continuations, eventually reaching the identify function that was specified as the initial continuation. This example demonstrates a crucial aspect of continuations. Continu- ations are simply functions that take some value as input, incorporate that input into the context, and continue with whatever rest of compu- tation they represent.
Now, you might be wondering why I chose this particular example.
Consider the following optimization: define times lambda l. Although this admittedly relies on the mathematical properties of mul- tiplication, it shows both the power of continuations and one reason why they should be used carefully. In this example, as soon as a zero is encountered in the list, all the rest of the computation, which is cap- tured in the continuation parameter c, is discarded. Continuations are capable of behaving like the dreaded goto of years past.
Continuations represented by closures break the tyranny of the call stack and provide clear mechanisms to combine inputs or to break out of a sequence that is no longer relevant. The names in this fragment are intended to reflect that there are exter- nal interfaces involved in obtaining some information about a customer. In a synchronous application, the execution of such code would pro- ceed by making the first request, waiting for the response, making the second request, waiting for the second response, and then combining those two responses into a decision, which is presumably sent some- place useful.
Generally speaking, such external systems are indepen- dent of each other, so the wait times can, in theory, be overlapped. However, the synchronous implementation ensures that the systems never attempt to make a decision without both pieces of information. This implementation, though, suffers from all sorts of problems with resource utilization and resilience to failure of the exter- nal systems for starters. A well-designed asynchronous system would fire off the two requests for external information at the same time and then make the decision once all the information was received.
For simplicity, I will assume we have a database that stores the cur- rent state of each customer, and I will assume that results from the external system are processed by some message receiver that queries the database for the current state of the customer. I will also leave out a fair amount of error handling. The state for a customer will be a continuation representing what com- putation is left and what context already exists. When the requests go out to the two external providers, the current state of customer Jay looks something like this: func status if status.
In this example, continuations are unnamed functions of one input parameter, the message status returned from an external system. The continuation for customer Jay, after the initial request, is a computa- tion that expects some status, figures out which it is, and then creates a new continuation, another unnamed function of one input parameter, that waits for the other kind of status. Once the other status arrives, the continuation still has the previous context and can make the decision. Collecting multiple independent inputs and combining them in a com- putation occurs frequently in business systems, particularly those modeled by workflows.
These systems often have complex logic to try to either accept inputs in any order or introduce artificial sequencing to simplify the process. This continuation model provides a simple but powerful mechanism to collect disparate inputs in whatever order and defer all other processing until the inputs have arrived. Now, some of you out there are probably saying that you could just record the intermediate results directly in the database.
There are several problems with the database ap- proach at an implementation level. The database constraints must be weakened to allow for incomplete records. The database design and the message formats can also be more readily decoupled using the continuation approach. The continuation representation makes it obvious what is still to come and what will be done with that information once it arrives.
Such informa- tion could be difficult to uncover if, for example, the same type of data was returned from two sources and had to be somehow reconciled. There are many other common patterns occurring in service-oriented applications that can be cleanly modeled with the concept of a con- tinuation. Customized exception handling is easy to implement in a continuation-based system. The caller supplies the exception handler in the form of a continuation that is invoked only if that particular exception is thrown.
The caller controls the context including whatever portions of the call stack are relevant that is used if that exception is encountered. Different continuations can be supplied for different exceptions. The notion of a success continuation is useful in a situa- tion where the application is waiting for a signal to finish but might have to process some unknown inputs before then. The standard con- tinuation simply continues to collect inputs until the completion signal is received.
The collected results are then given as input to the previ- ously supplied success continuation, and the computation completes. Many other patterns are possible as well. So, there has to be some downsides to this way of thinking. The biggest downside to continuations is actually considered a general downside to asynchronous systems. Understanding a continuation-based applica- tion is challenging because it is not always easy to know the order in which things happen. However, unlike the spaghetti code that resulted in the old days from nonstructured control flow, continuations include their context, and hence there is far less ambiguity about what might happen when the continuation executes.
More simply, although the order in which things happen may not be clear, what happens at any given continuation execution is clear. Another issue with continuations is the implementation-level support for them. Different language environments have varying levels of sup- port for continuations. Effectively, the creation of a continuation is run- time code generation. Many systems, particularly those that are com- piled, have limited support for full continuations.
However, although continuations are easily created using closures, more declarative rep- resentations of continuations are possible. Care must be taken in such circumstances, though, to not introduce too much complexity. Another caution regarding the creation of continuations: these con- structs embed in code some logic that could potentially be more readily captured declaratively.
Continuations can certainly implement work flows, for example. Some- times, however, utilizing a workflow framework may make more sense. The increasing popularity of service-oriented and event-driven archi- tectures is increasing the need for patterns and implementations to simplify asynchronous computation. Continuations, by capturing both data and control contextual information, provide a clean way to think about asynchronous computation. Scheme implementation.
Scheme resources. Continuations resources. Continuations in web applications. We have this horrible balancing act. On the one hand we really need simplicity, and on the other hand we really need power. And those are evil twin brothers of each other. Building systems that have a lot of power just sort of attracts complexity.
James Gosling speaking about Java vs. The Case for Groovy by Scott Davis. Scott Davis is the editor in chief of aboutGroovy. He is also an author and independent consultant. He is passionate about open source solutions and agile development. Scott is a frequent presenter at international conferences and local user groups. Politics are complicated. Society is com- plicated. And, yes, our industry is getting more complicated by the year. Do you remember your first program? I was quite pleased with it at the time. After all, it ran flawlessly, and its logic was irreproachable.
Ant or Maven to build it? Where is he going to deploy it—JBoss? Should it be fronted by Apache? Where are the unit tests? So, why did you choose Java? What made the step up in complexity worth it? Many would suggest power. James Gosling the father of Java makes that point in the quote at the beginning of this chapter.
Rather than seeking to be complex, he says that Java seeks to be powerful, and complexity is just an unfortunate byproduct.
At the risk of sounding contrarian, I argue that the beauty of Java is its simplicity and its power—not the simplicity of writing applications in it but the simplicity of deploying applications written in it. I can drop a JAR onto my classpath, and it just works. I can write a web application on my Mac. I think the assumption that the spectrum runs from easy to powerful is flawed: the units of measure are mixed. The spectrum should run from easy to complex.
WORA gives us at least two aspects of the development process to measure: how easy is the application to write, and how easy is the application to run? Your definition of power then rests on how you weight the criteria. How easy is it to add new functionality to the sys- tem?
Will it be easy to maintain over the life of the product? Can it be unit tested easily? Can it easily be integrated with my existing systems? Can it easily be integrated with my existing development staff? Is the code easy to read? I could go on and on with this exercise. Maybe you have your own crite- ria to add.
Regardless of what is included in the final evaluation, the power of the system is measured paradoxically by how many of the decision criteria end up being easy. In idiomatic Java, it takes me nearly 35 lines: import java. BufferedReader; import java. FileNotFoundException; import java. FileReader; import java. Of course, I could shorten this example by a few lines here and there. I could import java. I could catch Exception e. I could bend stylistic conventions by moving single-line blocks up and consolidate multiple closing curly braces onto a single line.
It just comes in at the wrong level of abstraction for many common aspects. If you are doing greenfield development with no existing database schema, no existing system to integrate with, and no legacy code to mesh with, then switching languages is a viable option.
- Neal Ford, ThoughtWorks.
- Achieving Your Potential as a Photographer: A Creative Companion and Workbook.
- 101 Amazing Mumford & Sons Facts.
- Research Methods Laboratory Manual for Psychology, Third Edition?
- Graham K. Rogers: eXtensions.
If, however, you are in an established Java shop, these issues can be showstoppers. After ten years of treating Java as a language, we are moving into a new era where Java is now a platform where you can use the language of. Can you call your Java code from the new language? Can you call the new language from your Java code? Can the new language be compiled into bytecode and stored in a JAR?
- Neal Ford | LibraryThing.
- Workbook on Cointegration (Advanced Texts in Econometrics);
- Blog @ Codonomics: ;
- The Burning Library: Essays;
- Recently added;
And perhaps most important, how complementary is the new language to eyes used to looking at Java? Complexity, it seems, is in the eye of the beholder. If you already know the intricacies of Ruby, then JRuby is a step toward simplicity: use Java for its strengths, and leverage JRuby where it helps. Granted, this is not an insurmountable task, but it does add complexity in the short term.
You end up betting that the long-term gains will be worth the short-term costs. But what if there was a simpler, more expressive language that was tar- geted at Java developers? Something that looks mostly like Java with just a touch of syntactic sugar, rather than something completely for- eign? More a new dialect of Java than a new language?
But before I get into the nitty-gritty details of the language, I should allow it to introduce itself. How does Groovy solve the previous Java problem of opening a file, walking through it line by line, and printing out the results? These three lines of code in Groovy which could technically be one solve what it took Java more than thirty to do. And println , as the name implies, prints out the result. To create the script, type it in the text editor of your choice. To run it, type groovy WalkFile at a prompt.
No compiling. No classpath. No worries. If you prefer, you can compile this code. You can type groovyc WalkFile. The syntax should look shorter than Java but still familiar. Variables are duck typed11 —no type declaration is required. Semicolons are optional. Even the familiar System. Closures are available in many languages. In Groovy, they are often used as concise replacements for Java iterators. As a matter of fact, the File that we are dealing with is, in reality, a java.
Groovy decorates it with some additional methods such as each , but it is a pure Java File through and through. I could take this example all the way back up to the Java example with which I started. Groovy would compile it without complaints although it would gossip about you behind your back. If the Groovy syntax looks strange and increases complexity, dial it back to something more Java-like.
If the Java syntax looks too verbose and cumbersome, mix in Groovy. Download12 the latest version of Groovy, and unzip it to the direc- tory of your choice. Type groovy - -version to verify that everything is OK, and you are off to the races. Look for groovy-all-[version]. Copy it to your lib directory, and you are set. Most modern IDEs and text editors have Groovy plug-ins.
Plug-ins for. Groovy even ships with a couple of command-line tools to help. Type groovysh to play around with the Groovy shell. Object public int java. String public boolean java. String java. Our visit to the shell shows off some additional language features. Groovy also has strong metaprogramming support. The last command demonstrates getting a list of all the methods of the class and using the each closure to print them out. In the earlier file example, I named the closure parameter line for clarity.
This time, I use the native it variable that gets assigned to non-named parameters. Groovy operates on the principle of least surprise; once you know how to iterate through a file using each, you come to expect it on all col- lection-like objects. The Groovy website is a great source of code snippets and samples. All three of the previous examples are valid String variables.
For the definitive language reference, pick up a copy of Groovy in Action,18 written by the leaders of the Groovy project. To keep up with the latest Groovy news, swing by aboutGroovy. This whirlwind tour of Grails will give you a taste of how quickly you can have a website up and running. Grails is as easy as Groovy to install.
Buy @ Amazon
It includes Hibernate. It includes Spring. It includes Sitemesh. It includes Quartz for schedul- ing. It includes the Ajax libraries Prototype, Script. Grails even includes its own copy of Ant. Literally everything you need to get started is included in the download. To set up your initial application, type grails create-app. The grails-app directory is where your Model-View-Controller code will ultimately live. Unit and functional tests live in grails-tests. Hibernate and Spring configuration files live in the eponymous directories.
Index of /pdf/Gentoomen Library/Programming/Pragmatic Programmers/
You can drop additional JARs into the lib directory. Type grails create-domain-class to create your first class. Type book when prompted for the name of the class. Pull it up in the text editor of your choice, and add a few fields. This is the only change you need to make to the application before you have a fully functional website that offers complete create, retrieve, update, and delete CRUD capabilities. Notice that there is no need to hand-code getters and setters. Grails ensures that the fields are private and through metaprogramming dynamically creates the expected methods: String getTitle , void setTitle String title , and so on.
To complete the application, type grails generate-all to set up a controller and put the boilerplate view code in place. Again, be sure to type book when prompted. That is it. You have a rudimentary bookstore in place. Type grails run- app to start the web server. By default, Jetty starts on port If that port is already in use, type grails -Dserver.
See Figure 5. There is so much more you could do with this application. You could create authors and publishers and allow GORM to manage the rela- tionships for you. Of course, the autogenerated views would make the relationships seamless in the browser as well. You could type grails console to poke around your live website from a command prompt. He takes you through every aspect of creating a full- featured Grails application.
And like Groovy, there is always more than. The beauty of Grails and Groovy as well is that you are almost never painted into a corner. Use your syntax slider to adjust things to the optimal level. I feel like we were just getting into the groove of Groovy. Groovy is a first-class citizen in Spring 2. You can implement your rules in Groovy in JBoss Rules a.
In the blogging space, Blojsom sup- ports it. JSPWiki has a Groovy plug-in. Because Groovy and Java are so similar, adding support for Groovy is a usually a minor task at best. Groovy will almost certainly be coming to a technical conference near you. The No Fluff Just Stuff tour has featured it prominently in the past whether it was me, Venkat Subramaniam, Andy Glover, or one of my other fellow speakers , and this year will be no different. JavaOne has had Groovy talks ranked in the top ten for the past several years running.
The Spring Experience offers several presentations showcas- ing Groovy. Grails eXchange is scheduled for late May in Lon- don. Three Groovy books went to print in early , and more are in the pipeline. Visibility in the blogosphere has risen as Groovy moved toward a 1. There is no glory in complexity. Power and com- plexity have been conflated for too long. Choose the solution that is both easy and powerful.
Most important, define easy on your terms. It offers full bidirectional integration with Java. It offers a nearly flat learning curve for experienced Java developers. But those are my sliders, not yours. Label your sliders accordingly, and pick the best solution that most fully defines powerful for you.
duck typing - Wiktionary
Kathy Sierra: Creating passionate users. Languages for the JVM. Groovy GDK. Groovy API Docs. Dynamic Languages in Java6. Brian Sletten is a liberal arts—educated software engineer with a focus on forward-leaning technologies. He has a background as a system architect, a developer, a mentor, and a trainer. Industry leaders, influential com- panies, marketing folks, and technologists with short-term memory loss or who are too young to remember the last time something like this was done pick up the scent of hype and run with it. It lauds those who refuse to suck up to the authorities in favor of telling it like it is.
In the story, a vainglorious emperor is suckered by a couple of thieves who convince him that they can weave such exquisite fabric2 that it becomes invis- ible to those who are stupid or in a lower class. The ruler pays these shysters large amounts of money, puts on the imaginary clothes, and then parades around town in his underthings believing he is wearing top fashion.
His subjects are afraid to appear stupid or low class, so they play along with the fantasy. They applaud him and comment on what fine rai- ments such a fine emperor is wearing. A lone child, lacking an aware- ness or fear of consequences, asks everyone what they are talking about. He points out the obvious fact that the emperor is not actu- ally wearing anything. As this truth is publicly acknowledged, everyone becomes embarrassed and goes about their business.
We need to remember the example of the young child and stop to ask questions about what we are all talking about. I have no real beef with two-thirds of the web services holy trinity. Furthermore, Web Services Description Language WSDL is an accept- able mechanism for defining contracts when you need to specify the inputs and outputs of your service. The fact that we have tools to gen- erate code for consuming these services in languages such as Java, C , and Ruby is often used as an argument in favor of these technolo- gies. The third part of the trinity, UDDI, is simply a wrong-headed solution to publishing and querying metadata about web services.
Many of the problems that I see with the standard technologies are direct consequences of their design goals. By decontextualizing re- quests into language- and transport-independent messages, we are required to encumber the messages with unnecessary amounts of state. Once we do that, we then need ways to verify that the state can be trusted in a context-free request which involves more state.
Much of the pain in web services emerges from these early decisions and the accretion of features that grow like a pearl in an oyster. Although this pearl has grown impressively large in the last few years, the quality and luster are lacking. My real issue with the current stack is that we are ignoring technologies that already exist, creating new ones that do not need to exist, and still not achieving the mythical interoperability we have been promised.
There is often as much dogma in this camp as others, but it is the pragmatic adherents who make the most sense to me. As such, I believe that in using the REST architectural style, we can achieve the goals of web services in most scenarios more simply, effectively, scalably, and with greater flexibility to support the content of the future. Many people are confused about REST, its goals, and how it is sup- ported. This chapter is not intended to flame the holy trinity as much as it is intended to try to clear the air around REST. I am not suggesting.
Shirkey uses the trope to suggest we keep creating new web service technologies on top of other web service technologies in order to achieve interoperability in the next layer which, when repeated, we will never achieve. I simply want to encourage architects, development managers, and businesspeople to stop to think about the approach they are taking and to make sure all the cost and complexity are worth it. The common understanding seems to be that it is a way of exposing services through URLs.
Although this is certainly part of the REST experience, it is by no means the full story. What this refers to is the passing back and forth of a representation of the state associated with a resource. A resource is anything that can be named: a file, a concept, a person, or an organi- zation. We identify resources through resource identifiers, more com- monly known as uniform resource identifiers URIs or the more spe- cialized uniform resource locators URLs.
Most people are familiar with web pages that they get to through a URL. They are unlikely, however, to stop to think about what is actually happening: they are identifying a resource and transferring a representation of it back for display in the browser. When all we do is a fetch a page, nothing is changed on the server by our request. You have taken a representation of your order specified in your browser and transferred it to the server. If there is no such order yet, the server will create it.
If you need to update your payment method, address, or quantity, you will send an update to the existing resource. OK, I have a bias! Although it is not generally my practice to recommend PhD theses to nonacademics, this is a very accessible document, and it really laid the foundation of this whole archi- tectural style. Noun Space The things to which we can refer are the nouns in the system.
We have the freedom to pick whatever meaningful naming schemes are appropri- ate for our domain or organization. The first URI might be a reference to all employees, where the second one refers to a specific employee. Note that at this point we are simply referring to things. The act of referring to something is distinct from the act of dereferencing it identifying and transferring the content. The mapping of the request for a resource to the representation to be returned is handled by the container.
What constitutes a good URI for a resource is a larger discussion than we have time for right now, but you should take the time to design your noun space references up front. Get buy-in from your user com- munity, and spend some cycles thinking about how resources might be organized in the future, how language choice for example English or French affects how resources are named, and so on.
Try not to base your resource hierarchies on organizational structures that are likely to change through company reorgs, new business priorities, and so on. Also, do not confuse the noun space with the verb space. The action of. The verbs manipulate the nouns. Although this is as you would expect it to be, it renders intermediary processors unable to make deci- sions without knowing how to process the messages in their entirety. This makes delegating caching and security checks through a network infrastructure an expensive and difficult process.
One obvious consequence of mini- mizing the number of actions in a system is to keep it simple. Doing so makes it much easier for developers to learn, and they become productive more quickly. Because a GET cannot8 have side effects, an intermedi- ary processor that has a cached copy of the resource can make a decision about whether to ask for another copy or return its copy. From a security perspective, an intermediary processor might offer a wider latitude on access to an information resource if it knows you cannot modify it.
You can POST to a processing engine like a servlet, which has the option of creating the resource. POSTs can also update a portion of a resource or append it such as an address or phone number. In reality, this should say should not, since you are free to develop pathological soft- ware; however, there is probably guidance against doing so somewhere. They do provide a good starting point for considering the manipulation of arbitrary resources, though. Interestingly, this is both a constrained interface and an open-ended interface.
Analysis Patterns: Reusable Object Models. Planning Extreme Programming. Joe Walnes. Patterns of Enterprise Application Architecture. Dr Jim Webber. Neal Ford. Gregor Hohpe. Alexei Vorontsov. Test-Driven Development in Microsoft. NET Microsoft Professional.
No Fluff Just Stuff 2007 Anthology p1 0
Dragos Manolescu. Less obvious, though, is a resurgence of interest in functional programming and functional languages. Just in the past two years, two compelling applications have appeared that are written in Haskell: PUGS an exploratory, prototype implementation of Perl 6 and Darcs a powerful, decentralized revision control system. Those systems have prompted many programmers to learn those languages, just so they can contribute to the projects, and the newcomers have been struck by the power and efficiency of functional languages.
Plus, interesting functional languages continue to appear.
No Fluff, Just Stuff Anthology: The 2006 Edition (Pragmatic Programmers)
To be efficient, languages had to be compiled, and programmers had to manage memory themselves. And, for that matter, early implementations of Java really were excruciatingly slow. But that was mostly due to immature implementations that used pure interpretation of bytecodes and naive garbage collection strategies. In modern Java-based systems, though, the slowness is due not to those characteristics of the language implementation, but to the libraries, frameworks, and platforms that have been built on top of Java. As far as interpretation goes, the just-in-time compilers JITs and dynamic optimization technologies employed by most Java implementations produce very fast machine code at runtime.
For most systems, you get much more performance benefit from good architecture than you do from fast code. Lisp and Smalltalk had their moments, as did bottom-up and iterative development, and the market chose a different direction. Here are just a few ideas about what went wrong the first time, and why things are different now. The kinds of design techniques and processes that are returning to prominence were originally used by individuals and very small teams, and began to show real weaknesses on more ambitious projects with larger teams.
Economies around the world, successful businesses, and even military organizations are pushing power and responsibility down toward the people in the trenches. The software development industry has learned the same lessons. Early implementations of dynamic languages were rather slow and required a lot of resources. It was much easier to build a C compiler that generated fast code than to build, say, a Smalltalk VM that performed similarly well. But implementation techniques have continued to advance, and the performance gap has shrunk dramatically. Not every dynamic or functional language has a state of the art implementation, but we know from examples like Common Lisp, Squeak Smalltalk, and Haskell that it is possible for such languages to be blazingly fast.
While language implementations have been getting faster, our cost models have been changing. The first time around, slow CPUs and expensive memory meant that computing resources were not to be wasted, and dynamic languages looked like the wrong tradeoff. Now, though, the balance has shifted. Productivity is much more valuable than it used to be in software development, and languages that save our time at the expense of some extra CPU cycles make a lot of sense. I could keep extending this list of reasons things happened the way they did.
The full list includes things like primitive tools, fractured communities, weak development practices, incompatible competing dialects, expensive implementations, the lack of any free versions that developers could play with, and more.