Pro Kotlin Web Apps from Scratch: Building Production-Ready Web Apps Without a Framework 1st Edition August Lilleaas pdf download
Pro Kotlin Web Apps from Scratch: Building Production-Ready Web Apps Without a Framework 1st Edition August Lilleaas pdf download
https://ebookmass.com/product/pro-kotlin-web-apps-from-
scratch-building-production-ready-web-apps-without-a-
framework-1st-edition-august-lilleaas/
https://ebookmass.com/product/pro-kotlin-web-apps-from-scratch-august-
lilleaas/
https://ebookmass.com/product/learn-enough-ruby-to-be-dangerous-
michael-hartl/
https://ebookmass.com/product/pro-asp-net-core-3-develop-cloud-ready-
web-applications-using-mvc-blazor-and-razor-pages/
https://ebookmass.com/product/beginning-azure-functions-building-
scalable-and-serverless-apps-2nd-edition-rahul-sawhney/
Pro Kotlin
Web Apps
from Scratch
Building Production-Ready Web Apps
Without a Framework
—
August Lilleaas
Pro Kotlin Web Apps from
Scratch
Building Production-Ready Web
Apps Without a Framework
August Lilleaas
Pro Kotlin Web Apps from Scratch: Building Production-Ready Web Apps Without a
Framework
August Lilleaas
Oslo, Norway
Introduction������������������������������������������������������������������������������������������������������������xxi
v
Table of Contents
Using Lambdas���������������������������������������������������������������������������������������������������������������������� 23
Named Arguments Instead of Magic Numbers and Booleans����������������������������������������������� 24
Run Your Web App����������������������������������������������������������������������������������������������������������������� 25
Logging��������������������������������������������������������������������������������������������������������������������������������������� 26
Loggers on the Java Platform������������������������������������������������������������������������������������������������ 26
Configure Logging in Your Web App��������������������������������������������������������������������������������������� 27
Write to the Log from Your Own Code����������������������������������������������������������������������������������� 30
A Note on “Magic” XML Config Files������������������������������������������������������������������������������������� 32
Useful Error Pages���������������������������������������������������������������������������������������������������������������������� 33
vi
Table of Contents
vii
Table of Contents
viii
Table of Contents
ix
Table of Contents
Chapter 9: Building Traditional Web Apps with HTML and CSS���������������������������� 161
Patterns and Organization�������������������������������������������������������������������������������������������������������� 162
Generating HTML���������������������������������������������������������������������������������������������������������������������� 162
Using the kotlinx.html DSL�������������������������������������������������������������������������������������������������� 162
Using the Ktor HTML DSL���������������������������������������������������������������������������������������������������� 163
The Power of the DSL���������������������������������������������������������������������������������������������������������� 164
Operator Overloading���������������������������������������������������������������������������������������������������������� 165
Adding Custom Tags������������������������������������������������������������������������������������������������������������ 166
x
Table of Contents
xi
Table of Contents
xii
Table of Contents
Chapter 13: Setup, Teardown, and Dependency Injection with Spring Context���� 251
Why Spring and Dependency Injection?����������������������������������������������������������������������������������� 252
Setting Up Spring Context��������������������������������������������������������������������������������������������������������� 253
Adding Your Data Source���������������������������������������������������������������������������������������������������������� 254
lateinit in Kotlin������������������������������������������������������������������������������������������������������������������������� 256
Starting Your Web App��������������������������������������������������������������������������������������������������������������� 257
Extended Usage������������������������������������������������������������������������������������������������������������������������ 258
xiii
Table of Contents
Index��������������������������������������������������������������������������������������������������������������������� 313
xiv
About the Author
August Lilleaas has been building web apps, user interfaces,
and real-time systems since 2004 and mobile apps since the
app stores opened in the late 2000s. After picking up Clojure
in 2012, he left the frameworks and ORMs behind and
started to build web apps from scratch and has shipped to
production using Clojure, Groovy, Node.js, Elixir, and Kotlin.
He has worked as a consultant for a decade and is now an
independent contractor and startup founder.
xv
About the Technical Reviewer
Andres Sacco has been a professional developer since 2007,
working with a variety of languages, including Java, Scala,
PHP, Node.js, and Kotlin. Most of his background is in Java
and the libraries or frameworks associated with it, like Spring,
JSF, iBATIS, Hibernate, and Spring Data. He is focused on
researching new technologies to improve the performance,
stability, and quality of the applications he develops.
In 2017 he started to find new ways to optimize the
transference of data between applications to reduce the
cost of infrastructure. He suggested some actions, some of them applicable in all the
microservices and others in just a few of them. As a result of these actions, the cost was
reduced by 55%. Some of these actions are connected directly with the bad use of the
databases.
xvii
Acknowledgments
Thanks to my fiancée, Tina, who believes in me and lets me know. Thanks to Jonathan
Gennick for giving me the opportunity to become a technical writer. Thanks to everyone
else at Apress for being a pleasure to work with. Thanks to Marius Mårnes Mathisen
for catapulting my career way back when, despite my complete lack of programming
education and professional experience. Thanks to Kolbjørn Jetne for further catapulting
my career, despite my complete lack of consulting experience. Thanks to Magnar Sveen,
Christian Johansen, and Alf Kristian Støyle for all the discussions, input, and inspiration
through the years. A special thanks to Finn Johnsen, who helped form most of the
patterns in this book and was a vital fellow traveler in my initial quest for escaping the
framework and bridging the gap between the old and the new.
Finally, thanks to my son, Tobias, and my daughter, Lone, who are awesome. And, at
my daughter’s request/demand, “Pappa er en bok.”
xix
Introduction
Welcome to Pro Kotlin Web Apps from Scratch! In this book, you’ll learn how to build
professional and production-grade web apps, completely from scratch, without the use
of big and unwieldy frameworks.
My personal web app journey started with frameworks, but when I learned more
about what goes on under the hood and grew weary of fighting framework bugs and
limitations, I started teaching myself how to build web apps from scratch instead. As it
turns out, frameworks aren’t a requirement!
You’re in good hands when you’re building from scratch, thanks to modern
programming languages like Kotlin and amazing third-party open source libraries. Back
in the day, you needed thousands of lines of boilerplate and XML configuration to wire
up a framework-less web app. No wonder people preferred frameworks! Nowadays,
though, all you need is a couple of handfuls of explicit code, completely free of bloat and
magic, that only does what you tell it to.
In Part I, you’ll set up a web app skeleton, completely from scratch. This code
base forms the basis for Part II, where you’ll learn a handful of patterns and practical
solutions that build on the skeleton from Part I. Part III covers how to choose the right
library and Kotlin tips and tricks that I didn’t get to cover in the preceding parts. Finally,
three appendixes explain how to replace some of the libraries chosen in Parts I and II, to
demonstrate that you have free rein to choose different libraries than me and still write
pro Kotlin web apps from scratch.
I’ve deliberately kept the chapter about Kotlin tips and tricks in Part III as short as
I’ve been able to manage. Instead, you’ll learn Kotlin tips and tricks in Parts I and II, and
you’ll learn how to build web apps from scratch alongside explanations of the various
Kotlin language constructs you’re using.
xxi
PART I
Setting Up a Development
Environment
In this chapter you’ll set up a development environment for Kotlin. You’ll install IntelliJ
IDEA, a Java Development Kit (JDK), you’ll write a small Kotlin program, and you’ll
compile and run it using the Gradle build system.
This chapter explains how to do everything using IntelliJ IDEA. For the other
chapters in this book, though, using IntelliJ IDEA is not a requirement. For example,
both the Eclipse IDE (integrated development environment) and Visual Studio Code
have Kotlin plugins available, made by the Kotlin community. If you choose to use
another editor, make sure that it supports auto-completion and automatic imports.
Extension functions are prevalent in Kotlin, and you must import them before you can
use them. You’ll avoid lots of tedious manual work if your editor can search and match
all available extension functions (auto-completion) and automatically add an import
statement when you select one of the auto-completed options (automatic imports).
3
© August Lilleaas 2023
A. Lilleaas, Pro Kotlin Web Apps from Scratch, https://doi.org/10.1007/978-1-4842-9057-6_1
Chapter 1 Setting Up a Development Environment
Figure 1-1. Download IntelliJ IDEA Community Edition for your platform
For more details on how to install and run IntelliJ IDEA, refer to the JetBrains
website. For example, the download page has a link with installation instructions in the
left sidebar, as seen in Figure 1-1.
4
Chapter 1 Setting Up a Development Environment
When you launch IntelliJ IDEA, you should see the splash screen shown in
Figure 1-2.
Click “New Project” to create a new Kotlin project using the built-in wizard in IntelliJ
IDEA, shown in Figure 1-3.
5
Chapter 1 Setting Up a Development Environment
Use your good taste and judgment to name the project, and adjust the options as
follows:
You need a JDK, and the easiest way to get one is to have IntelliJ IDEA download
one for you. Click the red “<No SDK>” dropdown in the New Project dialog shown
in Figure 1-3 and choose an appropriate JDK from the popup that appears, shown in
Figure 1-4. JDK 17 or JDK 11 is a good choice, as those are stable Long-Term Support
(LTS) releases.
6
Chapter 1 Setting Up a Development Environment
There are multiple vendors available. They are all full-fledged JDKs that adhere to
the JDK specifications. For the most part, it doesn’t matter which one you choose. The
differences lie in a handful of edge cases and different defaults. For most web apps, you’ll
be able to switch between vendors and not notice any differences. I personally prefer
Amazon Corretto, mostly out of habit. But I’ve used other vendors in real-world web
apps, such as Azul Zulu. I tend to choose whichever vendor is most convenient on the
platform I use, such as Azul Zulu on Azure, Amazon Corretto on AWS, and so on.
Make sure you choose a JDK of version 11 or newer. Versions 11 and 17 are both
Long-Time Support (LTS) releases, which means they’ll receive security updates longer
than other versions. And later in this book, you’ll use libraries that require at least
version 11 to work.
You can also choose an existing JDK if you have one installed. Alternatively, you can
manage JDK installations yourself, by using something like sdkman (https://sdkman.io/)
on macOS and Linux and Jabba (https://github.com/shyiko/jabba) on Windows.
Tip You can have bad luck and choose a JDK version that’s incompatible with the
Gradle version used by IntelliJ IDEA. For example, the 2021 version of IntelliJ uses
Gradle 7.1, which only works with JDK versions lower than 16. If this happens,
delete your project and start over, using a different JDK or Gradle version.
After IntelliJ IDEA finishes downloading the JDK, click the “Create” button at the
bottom of the New Project dialog shown in Figure 1-3, and your brand-new project
appears, as shown in Figure 1-5.
7
Chapter 1 Setting Up a Development Environment
Figure 1-5. IntelliJ IDEA after it has finished with project initialization
With this setup, IntelliJ IDEA won’t create sample code or pre-generated files, other
than a Gradle build system skeleton. All you have now is a way to compile and run Kotlin
code. And that’s all you need in this book. There’s no framework with tens of thousands
of lines of code that needs to run first to get anything done.
Tip Gradle is a build system for the Java platform. This is where you add third-
party code as dependencies, configure production builds, set up automated testing,
and more. Maven is also an excellent choice for building production-grade Kotlin
web apps. Most examples you’ll see in books and online documentation use
Gradle, though, and I’ve only used Gradle in real-world Kotlin apps, so that’s why I
use it in this book.
8
Chapter 1 Setting Up a Development Environment
• Create a package named after the project itself and put all your files
in it. A package is a namespace that tells code apart. This helps avoid
name conflicts with third-party code.
• File names are in upper camel case, also known as PascalCase, the
same as Java. Note that in the wild, it’s relatively common to see
underscores too, underscore_case. This book uses PascalCase
throughout.
In this book, you’ll place all your code in the package kotlinbook.
9
Chapter 1 Setting Up a Development Environment
• Choose File, choose the file template named simply “File,” name it
Main (IDEA will automatically add the .kt extension), and hit Enter
on your keyboard.
IntelliJ IDEA should now look like what’s shown in Figure 1-6.
10
Chapter 1 Setting Up a Development Environment
package kotlinbook
fun main() {
println("Hello, World!")
}
Tip You can also declare your function as fun main(args: Array<String>)
{ ... } if you want to read the command-line arguments passed to your
application. Java requires that your main function takes an array of strings, but
Kotlin does not have this requirement.
11
Chapter 1 Setting Up a Development Environment
Figure 1-7. A green play button next to the function name in IntelliJ IDEA shows a
runnable function
plugins {
kotlin("jvm") version "..."
application
}
12
Chapter 1 Setting Up a Development Environment
The application plugin needs to know where to find the main function. At the
top-level of build.gradle.kts (not inside the plugins block), declare the name of the
main class:
application {
mainClass.set("kotlinbook.MainKt")
}
Tip Did you notice the leaky abstraction? The application plugin is not aware
of Kotlin, and it needs to know the name of the compiled Java class file. To be
compatible and interoperable with the Java platform at large, the Kotlin compiler
turns Main into MainKt. A file Foo.kt that only declares the class Foo is compiled
to Foo.class. Any other scenario will generate FooKt.class.
To run the function with Gradle, use either of the two following methods:
You should now see the output of your application, either in your terminal or in the
IntelliJ “Run” output panel.
13
Chapter 1 Setting Up a Development Environment
When you see this progress bar, you should wait until it’s gone before you start
editing code.
IntelliJ IDEA knows a lot about your code. To gain that knowledge, it needs to analyze
your code first. When you type in new code, this will happen automatically (and so
quick you probably won’t notice). But when you create a new project or open an existing
project for the first time, IntelliJ IDEA might spend many minutes running analysis in the
background.
The editor is still active while analysis is running, so you assume that IntelliJ IDEA is
ready to go. But many core features won’t be available until the analysis is complete.
When the progress bar is gone, IntelliJ IDEA is ready to go, and you can now edit
code with all the features IntelliJ IDEA provides.
14
Chapter 1 Setting Up a Development Environment
15
Chapter 1 Setting Up a Development Environment
The icon will only be visible when there are changes made to build.gradle.kts that
IntelliJ IDEA is not yet aware of. But it’s easy to miss, so make sure you refresh your
Gradle project in IntelliJ IDEA every time you change build.gradle.kts.
Figure 1-10. Partially typing LocalTime in IntelliJ IDEA and getting auto-
completion
16
Chapter 1 Setting Up a Development Environment
Figure 1-11. Hit the Enter key, and the auto-completion will add the full class
name and add an import automatically
17
CHAPTER 2
This chapter will give you superpowers. You will get all the way to a working web app
with routing, views/templates, and logging. You’ll set the stage for what’s to come in later
chapters. It will just be you and your IDE, no starter kits or frameworks.
If you’re new to Kotlin, here are some language features you’ll see examples of in this
chapter:
• Lambdas
• Named arguments
Also in this chapter, you will learn the following about creating web apps:
• Setting up a web server, powered by Ktor, listening on port 4207
You’ll wire up all these things yourself, instead of having a framework do it for you.
If you’ve only used frameworks before, I envy you. Prepare to be surprised how little
manual wiring you need to do to get it done.
19
© August Lilleaas 2023
A. Lilleaas, Pro Kotlin Web Apps from Scratch, https://doi.org/10.1007/978-1-4842-9057-6_2
Chapter 2 Setting Up the Web App Skeleton
Choosing Ktor
You need a library to handle URL routing and to start up a web server to host your web
app. In this book, you’ll use Ktor. You can swap out Ktor for something else later if you
want, and in Appendix A you’ll learn how to use Jooby instead of Ktor. But in the rest of
the book, all the code you’ll write will use Ktor.
Ktor is one of the most popular libraries for web app routing in Kotlin. It has
everything you need to build production-grade web apps, and it’s written in Kotlin,
so it’s both convenient and powerful to use and makes use of all the relevant features
that Kotlin has to offer for building web apps. It’s also built to be highly scalable and
performant and is battle proven across a large number of real-world web apps.
And, most importantly, Ktor is a library, not a framework. Frameworks, such as
Spring Boot, typically start a web server automatically and use inversion of control to call
your code, somewhere deep down in tens of thousands of lines of framework code. The
point of this book is to learn how to do everything yourself, from scratch.
Interestingly, Ktor labels itself a framework. There aren’t any widely accepted
definitions of libraries vs. frameworks. The one I use in this book is that frameworks
automatically and implicitly do things for you, whereas libraries do nothing unless you
explicitly tell them to. Ktor nicely fits this definition of a library.
dependencies {
implementation("io.ktor:ktor-server-core:2.1.2")
implementation("io.ktor:ktor-server-netty:2.1.2")
}
20
Chapter 2 Setting Up the Web App Skeleton
Tip Remember to refresh the Gradle project in IntelliJ when you update build.
gradle.kts. Use the small popup that appears when there are changes that
Gradle hasn’t refreshed yet or open the Gradle tab and click the refresh button.
Listing 2-1. Start a web server in the application main function at src/main/
kotlinbook/Main.kt
package kotlinbook
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun main() {
embeddedServer(Netty, port = 4207) {
routing {
get("/") {
call.respondText("Hello, World!")
}
}
}.start(wait = true)
}
21
Chapter 2 Setting Up the Web App Skeleton
The code is plain and straightforward. You create an embedded Ktor server
that is using Netty for the server implementation under the hood and starts at port
4207. You set up routing, which means HTTP verb and path matching. Each route
has an implementation that generates a HTTP response. And finally, you start the
embedded server.
You don’t need to manually write the import statements. For example, when
you write embeddedSe and pause, IntelliJ IDEA will suggest embeddedServer. If you
choose the auto-completion from the dropdown, IntelliJ IDEA will also add an import
statement.
For clarity, the code in Listing 2-1 contains all the import statements needed to
make the code compile. For the remainder of this book, I’ll omit them unless there are
ambiguities (e.g., when there are two extension functions available with the same name,
but in different packages.)
22
Chapter 2 Setting Up the Web App Skeleton
fun main() {
embeddedServer(Netty, port = 4207) {
createKtorApplication()
}.start(wait = true)
}
fun Application.createKtorApplication() {
routing {
get("/") {
call.respondText("Hello, World!")
}
}
}
Using Lambdas
Lambdas are everywhere in Kotlin. In fact, you’ve already written a few of them. The
functions embeddedServer, routing, and get all take lambdas as arguments.
Lambdas are blocks of code, just like functions. They are created using curly
brackets, { and }. The main difference between lambdas and regular functions is that a
lambda does not have a name, but a function does.
23
Chapter 2 Setting Up the Web App Skeleton
There’s a convention in Kotlin for functions that take a lambda as their last
argument. Let’s look at the function get to demonstrate. It takes two arguments: a string,
denoting the path that triggers the route, and a lambda, which holds the code that
should execute when the web app handles a request at that path. One way of calling get
would be like this:
get("/", { ... })
Because it’s so common in Kotlin for functions to take a lambda as their last
argument, there’s a more convenient way to pass them to functions. Instead of placing
the lambda inside the parentheses of the function, you can place it after:
get("/") { ... }
This is particularly useful for functions that only take a lambda. An example of this is
the routing function. It’s nice to be able to skip the parentheses entirely.
It’s common for Kotlin programmers to put the lambda outside the parentheses. In
fact, IntelliJ IDEA will out of the box show a warning if you put a tailing lambda inside
of the parentheses. You can disable this warning if you want to, but it’s a good idea to
follow this convention if you want to make your code as readable as possible to other
programmers.
embeddedServer(Netty, 4207) {
createKtorApplication()
}.start(true)
A common name for Booleans and numbers passed to functions in this manner is
magic Booleans and magic numbers. It’s not immediately obvious to the reader what a
Boolean means when it’s passed to the function start() and what a number means in
the second argument passed to embeddedServer().
24
Chapter 2 Setting Up the Web App Skeleton
To make it easier to understand what these numbers and Booleans mean, you can
pass them as named arguments instead:
You can’t name it anything you want. It must be the same as the name of the
argument in the implementation of the function.
Figure 2-1. Your web app is up and running and responding to the port defined in
your code
25
Chapter 2 Setting Up the Web App Skeleton
Logging
High-quality logging is a vital component of production-grade web apps. It can make or
break your ability to find out what happened when errors happen in production.
When you run your application, the console prints the error messages shown in
Figure 2-2.
Figure 2-2. SLF4J issues an error message when your application runs
In this section, you’ll learn about logging and configure your application to output
useful information from third-party code, as well as logging from your own code.
26
Chapter 2 Setting Up the Web App Skeleton
of SLF4J loggers. But you haven’t configured logging yet, so SLF4J prints the error
messages seen in Figure 2-2 to let you know that SLF4J received log statements but isn’t
able to output them.
The Java platform has standardized on using SLF4J, and libraries and frameworks
will pull in the SLF4J library and use it to perform its logging.
To see actual log output, you need to add a logging implementation. There are many
different implementations available. The most widely used ones are Logback and Log4j.
SLF4J searches the class path for a logging implementation. The class path is where
the Java platform runtime can find all compiled code from your own source code, as
well as code from third-party dependencies. SLF4J will scan the class path for the class
file org/slf4j/impl/StaticLoggerBinder.class. The logging implementation you choose will
provide this file so that SLF4J can find it and wire it up. SLF4J will then forward all the log
statements it receives to the logging implementation, so that the logging implementation
can display the log messages.
Log levels are a hierarchy of severity levels. A logging statement always has a log
level. The available log levels are trace, debug, info, warning, error, and fatal. The log
levels separate debugging output and information about what your system is up to from
important warnings and critical errors.
You can use log levels to differentiate output from distinct parts of your code. For
example, you can tell the logging implementation to use the warning level for a given
module. The log level hierarchy then dictates that it will hide all levels below warning
(trace, debug, and info) and that the only visible log messages will be those at the
warning level and above (warning, error, and fatal).
dependencies {
implementation("ch.qos.logback:logback-classic:1.4.4")
implementation("org.slf4j:slf4j-api:2.0.3")
27
Chapter 2 Setting Up the Web App Skeleton
Tip You don’t have to add SLF4J as a dependency. Ktor already depends on
SLF4J, and the Gradle build system will make all transitive dependencies (i.e.,
dependencies of dependencies) available to your own code as well. But later,
you’ll call code from SLF4J directly, and it’s considered good hygiene to add direct
dependencies in build.gradle.kts to all code you call directly.
When you restart your web app, you’ll no longer see a warning from SLF4J. Instead,
you’ll see actual log output, like what you can see in Figure 2-3.
Figure 2-3. Logback fills your logs with verbose information because you haven’t
configured Logback yet
The log output visible in Figure 2-3 is from Netty, the server implementation used by
Ktor. In other words, what you see is the log output from a dependency of a dependency,
multiple steps away from your own code. The ability to investigate what all parts of the
system are up to is what makes logging so useful.
The most common way to set up a logging implementation is to use the info level
for all third-party code and the debug level for your own code. Debug log statements
from third-party code are usually not relevant unless you’re working on changes to that
28
Chapter 2 Setting Up the Web App Skeleton
code or you’re debugging an issue with an unknown cause. For your own code, the
debug level log output is truly relevant, as you are in fact working actively on changing
that code.
To configure Logback, you need to add an XML config file to src/main/resources/
logback.xml. Listing 2-3 shows an example of a valid Logback config file.
<configuration>
<appender
name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender"
>
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
%msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
The <appender> in Listing 2-3 tells Logback where to write the log output. You can
tell Logback to write to files and even send emails. Here, you configure Logback to
simply write logging output to the console. This is the most common configuration for
production setups as well, as most production environments will have facilities to make
console output available to developers.
The <root> logger in Listing 2-3 is the default logger that Logback will use for all
code – your own, as well as third-party dependencies – that does not have a specific
logger configuration. It’s set to the info level, which means Logback will only show
statements at info, warn, error, and fatal.
The statement <logger name="kotlinbook" level="DEBUG"/> in Listing 2-3
overrides the <root> logger for all logging statements coming from kotlinbook. This
means Logback will show all log statements for your own code at the debug level
and above.
29
Other documents randomly have
different content
It was, as I have said, a fine autumnal day. The sky was clear and serene.
The forests had put on their sober brown and yellow, while some trees of
the tenderer kind had been nipped by the frost into brilliant dyes of orange,
purple, and scarlet. Streaming files of wild ducks began to make their
appearance high in the air. The bark of the squirrel might be heard from the
groves of beech and hickory, and the pensive whistle of the quail at
intervals from the neighboring stubblefields.
The small birds fluttered, chirping and
frolicking from bush to bush, and tree to tree,
gay and happy because of the plenty and
variety around them. There were the twittering
blackbirds, flying in sable clouds; and the
golden-winged woodpecker, with his crimson
crest and splendid plumage; and the cedar
bird, with its red-tipped wings and yellow-
tipped tail; and the blue jay, in his gay, light-
blue coat and white underclothes, screaming
and chattering, nodding and bowing, and
pretending to be on good terms with every
songster of the grove.
As Ichabod jogged slowly on his way, his
eye ranged with delight over the treasures of
jolly autumn, On all sides he beheld vast store
of apples,—some still hanging on the trees, Ichabod and Gunpowder.
some gathered into baskets and barrels for the
market, others heaped up in rich piles for the cider press. Farther on he
beheld great fields of Indian corn, with its golden ears peeping from their
leafy coverts, and holding out the promise of cakes and hasty pudding.
There, too, were multitudes of yellow pumpkins turning up their yellow
sides to the sun, and giving ample prospects of the most luxurious of pies.
And anon he passed the fragrant buckwheat fields, breathing the odor of the
beehive; and as he beheld them, he dreamed of dainty slapjacks, well
buttered, and garnished with honey, by the delicate little dimpled hand of
Katrina, the daughter of Mynheer Van Tassel.
Thus feeding his mind with many sweet thoughts and “sugared
suppositions,” he journeyed along the sides of a range of hills which look
out upon some of the goodliest scenes of the mighty Hudson. The sun
gradually wheeled his broad disk down into the west. A few amber clouds
floated in the sky, without a breath of air to move them. The horizon was of
a fine, golden tint, changing gradually into a pure apple-green, and from
that into the deep-blue of the midheaven. A slanting ray lingered on the
woody crests of the precipices that overhung some parts of the river, giving
greater depth to the dark gray and purple of their rocky sides.
Then the harsh voice spoke: “Beware! beware! and think twice of what
you are doing. Evil as well as good will come from this invention upon
which you have set your heart. Instead of being a blessing to mankind, it
will prove to be a curse. Pause and consider before you place in the hands
of sinful and erring men another instrument of evil.”
Gutenberg’s mind was filled with distress. He thought of the fearful
power which the art of printing would give to wicked men to corrupt and
debase their fellow-men. He leaped to his feet, he seized his hammer, and
had almost destroyed his types and press when the gentle voice spoke again,
and in accents loud enough to cause him to pause.
“Think a moment,” it said. “God’s gifts are all good, and yet which one
of them is not abused and sometimes made to serve the purposes of wicked
men. What will the art of printing do? It will carry the knowledge of good
into all lands; it will promote virtue; it will be a new means of giving
utterance to the thoughts of the wise and the good.”
Gutenberg threw down his hammer and set to work to repair the mischief
that he had done. But scarcely had he put his printing machine in good
order when other troubles arose. He was in debt, and he had difficulties
with the town officers. His goods were seized upon; his types were
destroyed; and he was at last obliged to return penniless to his old home in
Mayence.
V. JOHN FUST.
In Mayence, Gutenberg had an old friend named John Fust, who was a
goldsmith and very rich. With this man he soon formed a partnership, and a
printing office much better than the one at Strasburg was set up. Several
books, most of them on religious subjects, were printed and sent out, and
the business was soon in a flourishing condition.
But Gutenberg’s troubles were not yet ended. There were a great many
people who were opposed to his new way of making books. The copyists
who made their living by transcribing books were very bitter against it
because it would destroy their business. They formed a league to oppose the
printers, and before long drove Gutenberg out of Mayence.
After wandering to various places in Germany, he at last gained the
friendship of Adolphus, the Elector of Nassau, who took a great interest in
his plans. A press was set up at the court of the Elector, and there Gutenberg
worked for several years, printing volume after volume with his own hands.
But his invention did not bring him wealth. When he died at the age of
sixty-nine years, he left no property but a few books which he had printed.
His partner, John Fust, had been much more fortunate. He had set up
another press at Mayence, and in spite of the copyists and their friends was
printing many books, and reaping great profits from their sale. One summer
he printed some Bibles and took them to Paris to sell. They looked very
much like the manuscript copies made by the copyists, for it was to the
interest of the printers to pass off their books as manuscripts. People were
astonished when Fust offered to sell his Bibles at sixty crowns, while the
copyists demanded five hundred. They were still more astonished when he
produced them as fast as they were wanted, and finally lowered the price.
The copyists were very bitter against him.
“He is a magician!” they cried. “No one but a magician could do this.”
And so the officers were sent to arrest him and search his rooms. They
found a great many Bibles and some red ink.
“There is no doubt about it,” said the officers. “This is blood, and the
man is a magician.”
In order to save himself from being burned as a wizard, Fust was obliged
to go before the Parliament of Paris and tell all about his new method of
making books, and how he used the red ink for embellishing the borders of
the pages.
It was thus that the art of printing by movable types first became known
to the world.
THE WANDERER.
Upon a mountain height far from the sea
I found a shell,
And to my listening ear the lonely thing
Ever a song of ocean seemed to sing,
Ever a tale of ocean seemed to tell.
“Sir,” he said, “I saw nothing but the waves lapping on the beach, and
the water rising and falling among the reeds.”
“Ah, traitor untrue,” said King Arthur, “now thou hast betrayed me
twice. Who would have thought that thou, who hast been so near and dear
to me and art called a noble knight, would betray me for the riches of the
sword? But now go again quickly, for I am chilled with cold, and my life is
in danger through thy long delay. And if thou dost not do my bidding, and I
ever see thee again, I will slay thee with my own hands; for thou, for the
sake of my rich sword, would see me dead.”
Then Sir Bedivere departed; and he quickly took the sword and went to
the water side. Then he wrapped the belt about the hilt, and threw the sword
as far into the water as he could. And there came an arm and a hand above
the water, and caught the sword, and shook it thrice and brandished it. Then
the hand, with the sword, vanished in the water. So Sir Bedivere came again
to the king and told him what he had seen.
“Alas,” said the king, “help me from this place; for I fear that I have
tarried too long.”
Then Sir Bedivere took the king upon his back, and carried him to the
water side. And when they came to the water, a little barge was seen
floating close by the bank; and in the barge were many fair ladies, and
among them was a queen. All these wept and cried out when they saw King
Arthur.
“Now put me into the barge,” said the king; and this Sir Bedivere did,
with tenderness and care.
And three of the fair ladies received him with great mourning. Then that
one who was the queen said: “Ah, dear brother, why have you staid so
long? Alas, I fear lest this wound on your head has been chilled over much
with the cold!”
Then they rowed from the land, and Sir Bedivere watched them. And he
cried: “Ah, my lord Arthur! What shall become of me, now you go away
and leave me here alone among my enemies?”
“Comfort thyself,” said the king, “and do the best thou canst, for I can no
longer give thee help. For I go now into the vale of Avilion, to heal me of
my grievous wound. If thou never hear more of me, pray for my soul.”
But the ladies and the queen wept and cried in a way that was piteous to
hear. And when Sir Bedivere lost sight of the barge, he wept bitterly; and,
weeping, he went into the forest, where he wandered all that long night.
“Some men yet say,” continues Sir Thomas Malory, “that King Arthur is
not dead, but taken by the will of our Lord into another place. And men say
that he shall come again and shall win the holy cross. I will not say it shall
be so, but rather I will say that in this world he changed his life. But many
men say that there is written upon his tomb a verse in Latin, which when
turned into English, is this: ‘Here lieth Arthur, that was and is to be King.’ ”
BIOGRAPHICAL NOTES.
George Bancroft: An American historian. Born at Worcester,
Massachusetts, 1800; died, 1891. Wrote “History of the United States from
the Discovery of the Continent” (10 vols.).
Daniel Boone: The pioneer of Kentucky. Born in Pennsylvania, 1735;
died in Missouri, 1820.
William Cullen Bryant: An eminent American poet. Born in
Massachusetts, 1794; died, 1878. Wrote “Thanatopsis” and many other
short poems. Was one of the editors of the “Evening Post” (New York) for
more than fifty years.
John C. Calhoun: An eminent American statesman and orator. Born in
South Carolina, 1782; died, 1850.
Richard Henry Dana, Jr.: An American lawyer and author. Born at
Cambridge, Massachusetts, 1815; died, 1868.
Charles Dickens: An English novelist. Born at Landport, England,
1812; died, 1870. His best novel is generally conceded to be “David
Copperfield.”
William Dimond: An English poet, remembered only for his “Mariner’s
Dream.” Died, about 1837.
Eugene Field: An American author. Born in St. Louis, 1850; died in
Chicago, 1895. Wrote “A Little Book of Western Verse,” “A Little Book of
Profitable Tales,” etc.
Robert Fulton: An American inventor. Born in Lancaster County,
Pennsylvania, 1765; died, 1815.
Charles E. A. Gayarré: An American historian. Born in Louisiana,
1805; died, 1895. Wrote a “History of Louisiana,” and several other works.
Sir Archibald Geikie: A Scottish geologist. Born in Edinburgh, 1835.
Has written “The Story of a Boulder,” “A Class Book of Physical
Geography,” and many other popular and scientific works on geological
subjects.
Thomas Grimke: An American lawyer and philanthropist. Born in
South Carolina, 1786; died, 1834.
Nathaniel Hawthorne: A distinguished American author. Born at
Salem, Massachusetts, 1804; died, 1864. Wrote “The Scarlet Letter,” “The
Marble Faun,” “The House of the Seven Gables,” “The Wonder Book,”
“Tanglewood Tales,” etc. His style has been said to possess “almost every
excellence—elegance, simplicity, grace, clearness, and force.”
Homer: The reputed author of the two great poems, the “Iliad” and the
“Odyssey.” Supposed to have been born at Smyrna, or Chios, about one
thousand years before Christ. The “Iliad” has been called “the beginning of
all literature.”
Washington Irving: An American author and humorist. Born in New
York, 1783; died, 1859. Wrote “The Sketch Book,” “History of New York
by Diedrich Knickerbocker,” “Tales of a Traveler,” “The Alhambra,”
“Columbus and his Companions,” “Mahomet and his Successors,” and
many other works.
Charles Kingsley: An English clergyman and writer. Born in
Devonshire, 1819; died, 1875. Wrote “Hypatia,” “Westward Ho!” “The
Heroes,” “The Water Babies,” “Alton Locke, Tailor and Poet,” “Madame
How and Lady Why,” several poems, and a volume of sermons.
Sir Edwin Landseer: The most famous of modern painters of animals.
Born in London, 1802; died, 1873. His pictures of dogs and horses have
seldom, if ever, been surpassed.
Edward George Bulwer-Lytton, Baron Lytton: A British novelist and
poet. Born in Norfolk, England, 1803; died, 1873. Wrote “The Last Days of
Pompeii,” “The Caxtons,” “My Novel,” and many other novels; also,
several volumes of poems, and two dramas, “The Lady of Lyons” and
“Richelieu.”
Sir Thomas Malory: A Welsh or English Knight, remembered for his
noble prose epic, “Morte d’Arthur,” which he translated from the French.
Born, about 1430.
John Henry Newman: An eminent English theologian. Born in London,
1801; died, 1890. Wrote many religious and controversial works, and a few
beautiful hymns. In 1879 he was made cardinal-deacon in the Roman
Catholic Church.
John Ruskin: A distinguished English author and art critic. Born in
London, 1819; died, 1900. Wrote “The Stones of Venice,” “Sesame and
Lilies,” “Ethics of the Dust,” “The Queen of the Air,” “Modern Painters,”
and many other works, chiefly on subjects connected with art.
Sir Walter Scott: A celebrated novelist and poet. Born in Edinburgh,
Scotland, 1771; died, 1832. Wrote the “Waverley Novels,” “The Lay of the
Last Minstrel,” “The Lady of the Lake,” “Tales of a Grandfather,” and
many other works.
Charles Sprague: An American poet. Born in Boston, 1791; died 1875.
Wrote several short poems, most of which are now forgotten.
Alfred, Lord Tennyson: Poet laureate of England. Born in Lincolnshire,
1809; died, 1892. Wrote “Idylls of the King,” “In Memoriam,” “The
Princess,” and many shorter poems; also the dramas “Queen Mary,”
“Harold,” and “Becket.”
Daniel Webster: American statesman and orator. Born in New
Hampshire, 1782; died, 1852. His most famous orations are those on
Bunker Hill, Adams and Jefferson, and his “Reply to Hayne.”
John Greenleaf Whittier: A distinguished American poet. Born at
Haverhill, Massachusetts, 1807; died, 1892. Wrote many volumes of poetry,
including “In War Time,” “Snow-Bound,” “Mabel Martin,” “The King’s
Missive,” and others.
Samuel Woodworth: An American journalist and poet. Born in
Massachusetts, 1785; died, 1842. He is remembered chiefly for his little
poem “The Old Oaken Bucket.”
WORD LIST.
THE MOST DIFFICULT WORDS IN THE PRECEDING LESSONS
PRONOUNCED AND DEFINED.
ebookmasss.com