Oct 18

Although Scala is tool-agnostic, the Scala community seems to have a preference for the Apache Maven build tool. I am not quite sure why. Given that most people who learn Scala come from a Java background, what could be more natural than using Ant for Scala development? As a tried-and-true build solution, Ant avoids the headaches and additional learning curve that comes with an unfamiliar build tool. Although I have spent considerable time with Maven as part of my job, Maven and I haven’t become friends, and we probably never will. I won’t go into the details of the how and why. Instead I’m going to present and explain a few Ant scripts for Scala development. If you are new to Scala, I hope that this will give you a headstart with your new Scala projects. After all, you have a new language to learn and little time to bother with tools.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<?xml version="1.0"?>
<project name="helloworld" default="run">
 
  <!-- root directory of this project -->
  <property name="project.dir" value="."/>
 
  <!-- main class to run -->
  <property name="main.class" value="app.HelloWorld"/>
 
  <!-- root directory of Scala installation -->
  <property name="scala.home" 
    value="C:\\Program Files\\Scala"/>
 
  <!-- location of scalatest.jar for unit testing -->
  <property name="scalatest.jar" 
    value="C:\\Program Files\\...\\scalatest-1.0.jar"/>
 
  <target name="init">
 
    <!-- derived path names -->
    <property name="build.dir" value="${project.dir}/build"/>
    <property name="source.dir" value="${project.dir}/src"/>
    <property name="test.dir" value="${project.dir}/test"/>
 
    <!-- scala libraries for classpath definitions -->
    <property name="scala-library.jar" 
      value="${scala.home}/lib/scala-library.jar"/>
    <property name="scala-compiler.jar" 
      value="${scala.home}/lib/scala-compiler.jar"/>
 
    <!-- classpath for the compiler task definition -->   
    <path id="scala.classpath">
      <pathelement location="${scala-compiler.jar}"/>
      <pathelement location="${scala-library.jar}"/>
    </path>
 
    <!-- classpath for project build -->   
    <path id="build.classpath">
      <pathelement location="${scala-library.jar}"/>
      <fileset dir="${project.dir}/lib">
        <include name="*.jar"/>
      </fileset>
      <pathelement location="${build.dir}/classes"/>
    </path>
 
    <!-- classpath for unit test build  -->
    <path id="test.classpath">
      <pathelement location="${scala-library.jar}"/>
      <pathelement location="${scalatest.jar}"/>
      <pathelement location="${build.dir}/classes"/>
    </path>
 
    <!-- definition for the "scalac" and 
      "scaladoc" ant tasks -->
    <taskdef resource="scala/tools/ant/antlib.xml">
      <classpath refid="scala.classpath"/>
    </taskdef>
 
    <!-- definition for the "scalatest" ant task -->
    <taskdef name="scalatest" 
      classname="org.scalatest.tools.ScalaTestTask">
      <classpath refid="test.classpath"/>
    </taskdef>
 
  </target>
 
  <!-- delete compiled files -->
  <target name="clean" depends="init" description="clean">
    <delete dir="${build.dir}"/>
    <delete dir="${project.dir}/doc"/>
    <delete file="${project.dir}/lib/scala-library.jar"/>
  </target>
 
  <!-- compile project -->
  <target name="build" depends="init" description="build">
    <buildnumber/>
    <tstamp/>
    <mkdir dir="${build.dir}/classes"/>
    <scalac 
      srcdir="${source.dir}" 
      destdir="${build.dir}/classes" 
      classpathref="build.classpath"
      force="never"
      deprecation="on"
    >
      <include name="**/*.scala"/>
    </scalac>
  </target>
 
  <!-- run program -->
  <target name="run" depends="build" description="run">
    <java classname="${main.class}" 
      classpathref="build.classpath"/>
  </target>
 
  <!-- build unit tests -->
  <target name="buildtest" depends="build">
    <mkdir dir="${build.dir}/test"/>
    <scalac 
      srcdir="${test.dir}" 
      destdir="${build.dir}/test" 
      classpathref="test.classpath"
      force="never"
      deprecation="on"
    >
      <include name="**/*.scala"/>
    </scalac>
  </target>
 
  <!-- run unit tests -->
  <target name="test" depends="buildtest" description="test">
    <scalatest runpath="${build.dir}/test">
      <reporter type="stdout" config="YFABRT"/>
      <membersonly package="suite"/>
      <!-- <reporter type="graphic" config="YFABRT"/> -->
      <!-- <suite classname="suite.TestSuite"/> --> 
    </scalatest> 
  </target>
 
  <!-- create a startable *.jar with proper 
    classpath dependency definition -->
  <target name="jar" depends="build" description="jar">
    <mkdir dir="${build.dir}/jar"/>
    <copy file="${scala-library.jar}" todir="${project.dir}/lib"/>
    <path id="jar.class.path">		
       <fileset dir="${project.dir}" >
         <include name="lib/**/*.jar"/>
       </fileset>
    </path>
    <pathconvert property="jar.classpath" pathsep=" " dirsep="/">
      <path refid="jar.class.path"></path>
      <map from="${basedir}${file.separator}lib" to="lib"/>		
    </pathconvert>
    <jar destfile="${build.dir}/jar/${ant.project.name}.jar" 
         basedir="${build.dir}/classes"
         duplicate="preserve">
      <manifest>
        <attribute name="Main-Class" value="${main.class}"/>
        <attribute name="Class-Path" value="${jar.classpath}"/>
        <section name="Program">
          <attribute name="Title" value="${ant.project.name}"/>
          <attribute name="Build" value="${build.number}"/>
          <attribute name="Date" value="${TODAY}"/>
        </section>
      </manifest>
    </jar>
  </target>
 
  <!-- create API documentation in doc folder -->
  <target name="scaladoc" depends="build" description="scaladoc">
    <mkdir dir="${project.dir}/doc"/>
    <scaladoc 
      srcdir="${source.dir}" 
      destdir="${project.dir}/doc" 
      classpathref="build.classpath"
      doctitle="${ant.project.name}"
      windowtitle="${ant.project.name}"/>
  </target>
 
  <!-- create a zip file with binaries for distribution -->
  <target name="package" 
    depends="jar, scaladoc" description="package">
    <zip destfile="${build.dir}/${ant.project.name}.zip">
      <zipfileset dir="${build.dir}/jar" 
        includes="${ant.project.name}.jar"/>
      <zipfileset dir="${project.dir}" includes="lib/*"/>
      <zipfileset dir="${project.dir}" includes="doc/*"/>
      <zipfileset dir="${project.dir}/txt" includes="*"/>
    </zip>
  </target>
 
</project>

Download “helloworld.scala” with Ant build file.

Fortunately, the designers of Scala provided built-in Ant tasks in the compiler library, which makes the integration of Ant straightforward. The XML code above shows the build.xml for a typical Scala standalone application, such as a GUI program or a console application. It is reasonably complete and it provides Ant targets for all common tasks:

  • build = compile your project and put class files into the ./build directory.
  • run = run program.
  • jar = create a startable jar archive from class files.
  • test = build and run unit tests (using Scalatest).
  • scaladoc = create API documentation from sources and put it into the in ./doc directory.
  • package = create a distributable zip archive that contains all dependencies plus Scaladocs.

The directory tree is kept as simple as possible:

Scala Project Skeleton
  • build - temporary directory for class files and other binaries
  • lib - contains external dependencies (*.jar files)
  • src - contains Scala source code tree
  • test - contains Scala unit tests
  • txt - contains files (such as license text) that are packaged with the distributable zip archive

If your project depends on external jars, all you have to do is to drop these into the ./lib folder. Ant will take care of creating appropriate class paths, entering them into the manifest of the startable jar file, and including them in the distribution package. The Scala library is packed automatically so that the resulting package can be deployed on computers that don’t have Scala installed (only a standard JRE is required). To use this Ant script on your computer, you need to change the values of the scala.home and scalatest.jar properties to match the location of your Scala and Scalatest installations (never mind the latter if you use another unit testing framework). If you are working in a team, it is good practice to put Ant properties into a separate properties file, so that the build file can be checked into a source code management tool. I have included them here for simplicity.

One of the advantages of using Ant is that it has very good integration with IDEs, such as Eclipse. The only twist is that Eclipse does not honour the classpaths defined in build.xml for its own incremental compilation process used to mark syntactical errors. Thus if you import the Ant project into Eclipse, you have to tell Eclipse about the dependencies using the Project/Properties/Java Build Path option.

Ant in Eclipse

Share and Enjoy:
  • Digg
  • del.icio.us
  • Technorati
  • Facebook
  • Mixx
  • Google
  • YahooMyWeb
  • Slashdot
  • LinkedIn
  • blogmarks
  • Live
  • description
  • StumbleUpon
  • Ma.gnolia
  • MisterWong
  • NewsVine
  • Reddit
  • Spurl
  • Yigg
  • E-mail this story to a friend!
Oct 5

Perhaps suggesting to eschew web frameworks for web application development is playing the devil’s advocate. Perhaps it is even foolish. To renounce the productivity boost one gets with a properly designed framework does not sound like sensible advice. Only ignorant script kiddies entertain such ideas. Well, for the most part that is true. A web framework does indeed simplify application development if it is chosen well. It does even more if it is designed well. It can provide architectural support for building maintainable applications. It can help with the plumbing and provide conceptual structure to guide the development process.

So, what speaks against using a web framework? Plenty actually, especially at the lower end of the spectrum and especially with dynamic languages. The main problem with web frameworks is that they add overhead. This means that the added functionality and structure is bought at the cost of performance degradation. The graveness of this problem depends on the system architecture. One  needs to keep in mind, that dynamic languages are interpreted at runtime, which makes them CPU-intensive and relatively slow. Because the life cycle of a script is essentially stateless and single-step, classes and data structures need to be rebuild and reloaded (in theory) at each request. In practice, this does not happen, because servers are designed to provide at least rudimentary caching. However, the runtime performance of interpreted languages is typically several magnitudes smaller than that of a compiled language, which magnifies the problem.

To illustrate my point, consider these benchmarks for PHP frameworks kindly provided by Paul M. Jones. According to these figures, a trivial PHP page is served by Apache 2 at a performance reduction of 43% compared to static HTML. The use of various PHP web frameworks further reduces performance by 85% - 95% compared to a PHP page that merely echoes content. Although it can be expected that these figures develop inverse logarithmically with increasing application code complexity, the slowdown is significant. PHP offers a number of remedies, such as  opcode caching, object caching, and products such as Zend Server, APC, and MCache, yet performance is unlikely to get even close to that of a compiled language.

Furthermore, there is the question whether the complexity of the project justifies the complexity introduced by a web framework. Would you use a web framework for building a guestbook script? Probably  not. What about a blog software? A photo gallery? A bulletin board? These types of applications are the mainstay of dynamic languages, such as PHP. It is the area where PHP really shines. Think of Wordpress, phpBB, Mediawiki, Drupal, osCommerce, Coppermine and other popular applications. They all have one thing in common: they don’t use a framework. Hence, before choosing a web framework for PHP development, it may be worth pondering if any is required. This suggestion may sound a bit contradictory, having just reviewed the Zend framework in a previous article. However, in my own practice I haven’t come across many complex PHP projects.

The commercial PHP projects I worked on during the last 10 years can roughly be divided into three categories: 1. extensions and customisations of open source packages, 2. intranet information systems, and 3. e-commerce systems and “catalogware”. Although the latter two may be considered candidates for web frameworks, the size of these projects was almost always small enough to do without. On several occasions, I chose to implement an “ultralight” MVC architecture by hand instead of using an out-of-the-box framework. The main reason for this was again performance. The “ultralight” approach is defined by implementing only the required functionality, which results in highly specialised design. In practice, this means slimming the controller, reducing DB abstraction to a thin wrapper around the native library, and foregoing a templating system in favour of embedded PHP.

The advantage of this approach is that you get separation of presentation and business logic, componentisation, and customisable control flow without the performance cost of full-blown framework. The disadvantage is that it is slightly more laborious to implement and less flexible. Don’t get me wrong. I have no problems imagining scenarios where I would want to use a PHP web framework such as the Zend framework. However, in these cases I’d probably be drawn towards using Java or (hopefully) Scala in the first place. In summary, I have found myself using PHP mostly in situations where a web framework seemed dispensable, while I have been using Java mostly in situations where a web framework seemed essential.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Technorati
  • Facebook
  • Mixx
  • Google
  • YahooMyWeb
  • Slashdot
  • LinkedIn
  • blogmarks
  • Live
  • description
  • StumbleUpon
  • Ma.gnolia
  • MisterWong
  • NewsVine
  • Reddit
  • Spurl
  • Yigg
  • E-mail this story to a friend!