<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jacob O'Bryant</title>
    <description>The latest articles on DEV Community by Jacob O'Bryant (@obryant666).</description>
    <link>https://dev.to/obryant666</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F259990%2F22a291e4-5368-4b23-bc94-9a352e2d8d1f.png</url>
      <title>DEV Community: Jacob O'Bryant</title>
      <link>https://dev.to/obryant666</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/obryant666"/>
    <language>en</language>
    <item>
      <title>What I've learned since quitting my job</title>
      <dc:creator>Jacob O'Bryant</dc:creator>
      <pubDate>Fri, 15 Nov 2019 17:11:27 +0000</pubDate>
      <link>https://dev.to/obryant666/what-i-ve-learned-since-quitting-my-job-1ckh</link>
      <guid>https://dev.to/obryant666/what-i-ve-learned-since-quitting-my-job-1ckh</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://jacobobryant.com/post/2019/reflections/"&gt;jacobobryant.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I got my bachelor's degree in 2017 and then worked for a year as a software engineer. Last January I quit and began working on a startup full-time with a friend I met while in school. I realized after a few months that we weren't a good fit as cofounders, so I bailed. I then spent some time trying to figure out what to do with my life. In June I decided to go all-in on my current startup, &lt;a href="https://lagukan.com"&gt;Lagukan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Several days ago, I discovered a potentially critical flaw in my startup idea. I might need to take a major change of direction (though I'm thinking of moving to an idea that will still solve some of the same problems). This kind of thing has happened to me quite a lot in the past year, so I thought I'd take this opportunity to do some introspection before I go head-down coding again.&lt;/p&gt;

&lt;p&gt;So, here are a few of the things I've been thinking about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spotify is actually pretty good&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've been in love with music since I was about 12. I started using Pandora while in high school. I discovered a lot of new music that way, but it was far from perfect. It was never able to fully adapt to my preferences (e.g. I love melodic hard rock and hate metal, a distinction that was utterly beyond Pandora), and it tended to play the same things over and over.&lt;/p&gt;

&lt;p&gt;I started doing music recommendation research while in college, culminating in a prototype that played from Spotify and my MP3 collection but used my own custom algorithm. It was nice, although it left a lot to be desired. I later tried using vanilla Spotify for a while and wasn't super impressed.&lt;/p&gt;

&lt;p&gt;Hence, I eventually decided to pursue my recommender system project as a startup (Lagukan). It seemed like a natural choice. I was encouraged by the response on Hacker News to my first prototype. &lt;a href="https://news.ycombinator.com/item?id=20585143"&gt;Here's a snippet&lt;/a&gt; from one of my favorite comments:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oh man... I haven't been able to find any recommendation algorithms that recommended songs I liked even 1% of. Spotify's is a trash fire. Last.fm's wasn't great. Pandora is okay.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pulling off a successful music company has been historically pretty difficult, but I was alright with that since I was working on something that was deeply meaningful to me.&lt;/p&gt;

&lt;p&gt;One of the most important issues in music recommendation (and more generally, in reinforcement learning) is balancing exploration (trying out new songs) with exploitation (playing songs you've listened to before). Lagukan has two separate algorithms for these tasks plus a parent algorithm that decides which sub-algorithm to use at any given moment. It's a delicate balance. Back when I was a Pandora user, they only really addressed exploration. Spotify seemed to have the opposite problem of doing too much exploitation.&lt;/p&gt;

&lt;p&gt;However, I've slowly realized that I was likely just using Spotify wrong. I've always had the assumption that a music player should be totally automatic: just hit play, skip what you don't want to hear right now, then the algorithm should do everything else. That's how I've built Lagukan, and that's how I tried to use Spotify—I almost exclusively listened to Daily Mix.&lt;/p&gt;

&lt;p&gt;This is a long-winded way of saying "I should've been using Discover Weekly."&lt;/p&gt;

&lt;p&gt;I had read several comments on HN saying that Spotify performed much better if you listen to Discover Weekly consistently. It makes sense—that's their solution for those who want automated exploration, and Daily Mix is for exploitation. Sure, it's not all wrapped up into a single totally automatic algorithm, but the overhead is pretty low.&lt;/p&gt;

&lt;p&gt;I've been using Spotify directly for the past few days, and it's been disturbingly effective. It's been seeded by Lagukan's exploration from the past month or so, but I'm going to try using just Spotify for several weeks and see how well it does. I'm open to the possibility of not needing Lagukan personally.&lt;/p&gt;

&lt;p&gt;Even if Spotify turns out to work well for me, there likely are other people for whom a better recommendation algorithm would still be valuable. But if I'm not one of those people, then I don't think I'll be able to generate the insights needed to help them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You should be comfortable with cutting your losses&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It sucks to put five months into a startup built on a false hypothesis, but it's better than sticking with it and running out of savings. I'd say it's also better than never taking the leap at all, because the losses often aren't.&lt;/p&gt;

&lt;p&gt;For one, my skills have grown far faster than they ever did while I was a student or an employee. I've been able to learn everything I wanted to in college but (ironically) never had the time for due to coursework, and I've discovered plenty of things that I'd like to dive into more. It's the most freeing educational experience I've had since I was a homeschooled teenager. I've also learned quite a bit about the industries I've been trying to enter, not to mention the emotional dynamics of not having any external validation from being an employee or a student.&lt;/p&gt;

&lt;p&gt;Despite failing over and over in the past year, I don't see any of it as a waste. It feels more like do-it-yourself grad school (minus the degree at the end). I don't think any other path would have been as good of an investment in myself.&lt;/p&gt;

&lt;p&gt;About three months ago, I started to get another idea for a recommender system startup that I actually think is more promising than what I've been doing. I stuck with Lagukan because I didn't want to get whipsawed, constantly switching ideas before getting traction. Even if I do ultimately decide to relegate Lagukan to side project status, maybe my work will turn out to have been optimal: I wouldn't have had this second idea if I hadn't dug into music recommendation.&lt;/p&gt;

&lt;p&gt;What about giving up too easily? You certainly shouldn't do that, but if you, in your heart, no longer believe in the idea, I think that's a pretty good indication that it's time to switch. I've been through many discouraging experiences with Lagukan, but this is the first time I've seriously doubted the validity of my core value proposition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It helps to articulate what you want to get out of your career&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm a huge fan of Paul Graham. I stumbled on his essays while in high school; it was the first time I ever heard about startups (and Lisp!). I like to think I'm still as ambitious as 15-year-old me reading his essays for the first time, but actually trying to start my own business without giving up requires that I understand why it's worth my time.&lt;/p&gt;

&lt;p&gt;First of all, I have to be a startup founder because right now there are certain things about the world that I'd like to fix, and it would kill me to spend my hours at a day job instead. But what else is important to me?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Working on my own projects. Even if I don't do it as a startup, I have to at least have lots of time for side projects. I love exploring and I'm a very self-motivated learner. I can't give up my freedom.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Working in Clojure. I was more language-agnostic when I graduated, but after a year each of doing Clojure and non-Clojure full-time, this is important to me.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Playing clarinet. I'd like to join an orchestra again, though I've put it on hold while I try to build a business. At some point I need to have at least an hour a day for practicing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Teaching. This is another thing I love doing, and it's high-impact. At a minimum, I need time to write guides and tutorials regularly. (On the other extreme, some kind of education startup is my backup-backup-plan for Lagukan).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all these demands, you can probably see another reason why doing a startup is so appealing to me: it'd be great to just make a lot of money all at once so I have freedom to work on whatever I want, regardless of if it's profitable or not.&lt;/p&gt;

&lt;p&gt;But if I get through all my startup ideas and fail each time, what's next? If Stripe offered me a 30-hour-per-week position writing Clojure, I'd probably take it. Barring that, I think consulting is the most likely way to hit all the bullet points. I would be fine alternating between my own projects and clients' projects. (I've also thought seriously about grad school... but I've decided against it because I'm interested in &lt;a href="http://www.paulgraham.com/desres.html"&gt;design, not research&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;The result of all this pondering is that my decision to continue being a startup founder is based on careful reason, not emotion alone (I'm not a fan of burn-the-ships). I'm confident that if I come to a point where the rational thing is to no longer be a startup founder, then I'll do something else and still be happy. That understanding helps me to not get so depressed when bad things happen, which is important since startups run on morale. Knowing that there are other good career alternatives also helps with cutting losses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coming up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've also developed my own opinions about cofounders, networking, idea validation, bootstrapping vs. VC... so let me know if you'd like to read a "part 2" of this article. Meanwhile I'll be building a prototype for my next idea. Fortunately, I should be able to release this one within a week or two. And if it works, Lagukan will likely make a good complementary product down the rode. I'll keep my fingers crossed.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>career</category>
    </item>
    <item>
      <title>A Brief History of Agile</title>
      <dc:creator>Jacob O'Bryant</dc:creator>
      <pubDate>Mon, 04 Nov 2019 15:37:27 +0000</pubDate>
      <link>https://dev.to/obryant666/a-brief-history-of-agile-1fnf</link>
      <guid>https://dev.to/obryant666/a-brief-history-of-agile-1fnf</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://jacobobryant.com/post/2018/agile/"&gt;jacobobryant.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;"Agile" development was a peculiar sport played by "software engineers," a type of indentured servant who made their living by tapping buttons all day instead of taking up a real career as a doctor, a lawyer or an actual engineer. Agile was created as a form of entertainment for Scrum Masters, software engineers who had been given special privileges in return for keeping the others in line.&lt;/p&gt;

&lt;p&gt;Like other sports of the time, Agile was divided into various phases of game play. Due to the indoor nature of button-tapping and the relatively low amount of energy required to do so, Agile was played year round. A 12-month season was separated into 4 quarters, each composed of 6 "sprints." Whoever scored the most points won the sprint, so each engineer's goal was to maximize the points they earned per day while minimizing the same ratio for their coworkers.&lt;/p&gt;

&lt;p&gt;Engineers could score points by completing grueling tasks. These tasks were called "stories" to make them sound more fun. Each story was assigned a certain number of points at the beginning of each sprint through a ritual called "estimation." Each engineer would vote on a number of points for the story, and then based on the votes, the group would decide how many points each story would ultimately be worth. Before deciding on a number of points, each engineer would have to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How hard the story was (both for them and for their coworkers)&lt;/li&gt;
&lt;li&gt;Who the story would likely to be assigned to&lt;/li&gt;
&lt;li&gt;How many points they thought the other engineers would vote on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each engineer hoped to receive stories that were easy for them but still worth a lot of points.&lt;/p&gt;

&lt;p&gt;This voting process was called "planning poker," so named because of the highly psychological nature of estimation and the large amount of bluffing involved. After the Scrum Master gave a countdown, each engineer would hold up a number of fingers equal to the number of points they thought the story should be worth. After removing outliers, the story was worth the average of the votes.&lt;/p&gt;

&lt;p&gt;A basic strategy was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Decide if you want the story to be worth many or few points.&lt;/li&gt;
&lt;li&gt;Gauge how many points the other engineers will vote on.&lt;/li&gt;
&lt;li&gt;Vote on a number of points that pulls the average in your desired direction
without turning your vote into an outlier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Being an outlier was very bad because it nullified your vote. In addition to eliminating your influence on the final worth of the story, nulls were considered unclean by many engineers. Nullified engineers were required to work from home for three days.&lt;/p&gt;

&lt;p&gt;In order to further humiliate outlying voters, they had to give an impromptu explanation for why they voted so ridiculously. These reasons were expected to be related only to the difficulty of the story, providing outsiders with the illusion that estimation was simply part of getting the job done. But for insiders, the humiliation damaged their ability to influence other engineers in future estimations.&lt;/p&gt;

&lt;p&gt;To heighten amusement for the Scrum Master, engineers were restricted to choosing votes that fell in a certain set of numbers called the "Fibonacci sequence," so called because the estimations were really just fibs.&lt;/p&gt;

&lt;p&gt;There were many intricacies in planning poker strategy, most of which fall outside the scope of this article. But there was at least one trick taken from professional rock-paper-scissors tournaments: an engineer could pretend to vote at the same time as the other engineers but really wait a split second longer; thus they could see what the other votes were and respond accordingly. Only those with more experience employed this tactic, as penalties for being caught were severe.&lt;/p&gt;

&lt;p&gt;After estimation was finished, it was a race (hence the term "sprint") to finish as many stories as possible while subtly hindering coworkers. One common tactic was to bring up "tests" right before a co-worker was about to finish a story. If the other engineers agreed, the co-worker would be forced to spend a day "testing" before marking the story as complete. During the test, engineers were buffeted by a series of impossible-to-answer questions such as "When will the current project be completed?"&lt;/p&gt;

&lt;p&gt;Like the gladiatorial games, Agile was high stakes. Engineers who won the most sprints would be promoted to "Senior Engineer," "Epic Engineer," and finally "Manager." Promotions came with respectable pay increases but also tougher competition. On the other end of the spectrum, a chart was used to keep track of engineers who didn't finish all the stories they were assigned each sprint. This was called a burndown chart because if the line on the chart reached the upper-right corner, the engineer with the highest point deficit would be burned.&lt;/p&gt;

&lt;p&gt;Eventually, engineers started to revolt and Agile fell out of practice. It was replaced by a new movement, the name of which was chosen to represent the end of the Agile burndowns: "Waterfall."&lt;/p&gt;

</description>
      <category>agile</category>
    </item>
    <item>
      <title>Learn Clojure with Web Dev</title>
      <dc:creator>Jacob O'Bryant</dc:creator>
      <pubDate>Mon, 28 Oct 2019 17:17:04 +0000</pubDate>
      <link>https://dev.to/obryant666/learn-clojure-with-web-dev-3f4n</link>
      <guid>https://dev.to/obryant666/learn-clojure-with-web-dev-3f4n</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://jacobobryant.com/post/2019/learn-clojure/"&gt;jacobobryant.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've created this document so that I have a single link I can give people for learning Clojure. It is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a work in progress&lt;/li&gt;
&lt;li&gt;not meant to be comprehensive&lt;/li&gt;
&lt;li&gt;opinionated/a reflection of how I do web development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm trying to help people get started without being overwhelmed by all the different options. I'll link to existing resources when possible, adding my own as needed.&lt;/p&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;basic terminal experience&lt;/li&gt;
&lt;li&gt;comfortable with HTML and CSS&lt;/li&gt;
&lt;li&gt;know a different programming language already&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hello world
&lt;/h3&gt;

&lt;p&gt;First, &lt;a href="https://clojure.org/guides/getting_started"&gt;install Clojure&lt;/a&gt;. Then type &lt;code&gt;clj&lt;/code&gt; to get an interactive prompt ("repl," short for read-eval-print-loop). In the repl, type &lt;code&gt;(println "hello world")&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ clj
Clojure 1.10.0
user=&amp;gt; (println "hello world")
hello world
nil
user=&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Instead of using the default repl, you can get an enhanced repl like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ clojure -Sdeps "{:deps {com.bhauman/rebel-readline {:mvn/version \"0.1.4\"}}}" -m rebel-readline.main
[Rebel readline] Type :repl/help for online help info
user=&amp;gt; (println "hello world")
hello world
nil
user=&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I recommend saving this as an alias, e.g. put the following in your &lt;code&gt;.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;repl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'clojure -Sdeps "{:deps {com.bhauman/rebel-readline {:mvn/version \"0.1.4\"}}}" -m rebel-readline.main'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Run from a file
&lt;/h4&gt;

&lt;p&gt;I recommend starting out with the &lt;a href="https://atom.io"&gt;Atom&lt;/a&gt; text editor.[1] After you install it, create a new project folder. Within that folder, edit a new file &lt;code&gt;src/web/core.clj&lt;/code&gt; with Atom. So your project folder should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree myproject/
myproject/
└── src
    └── web
        └── core.clj
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Put the following inside &lt;code&gt;core.clj&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;web.core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From the terminal, you can run the file like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd myproject
$ clj -m web.core
hello world
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Start learning Clojure
&lt;/h3&gt;

&lt;p&gt;For actually learning the language, I recommend &lt;a href="https://www.braveclojure.com/clojure-for-the-brave-and-true/"&gt;Clojure for the Brave and True&lt;/a&gt;. (It's available online for free at that link, though I liked having a hard copy).&lt;/p&gt;

&lt;p&gt;You can skip chapters 1 and 2. Work through chapter 3 before going on to the next section in this document. Fairly soon, make sure you also understand everything in chapters 4 and 5. These three chapters contain the fundamentals of the language.&lt;/p&gt;

&lt;p&gt;All of the remaining chapters are useful too. Make sure you understand them eventually. But for now, you can just skim them a bit and refer back as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start doing web dev
&lt;/h3&gt;

&lt;p&gt;I'll now show you the first fundamental of web development: how to generate HTML and CSS. We'll create a static landing page. This is a great first project because it's pretty simple, and generating HTML + CSS is much nicer in Clojure than in any other language. You could even extend this project into a personal blog/website if you like.[3]&lt;/p&gt;

&lt;p&gt;We need to add a library to your project. Create a file &lt;code&gt;myproject/deps.edn&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:deps&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trident/staticweb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:mvn/version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"0.1.18"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Change the contents of &lt;code&gt;core.clj&lt;/code&gt; to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;web.core&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;trident.staticweb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tsweb&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tsweb/html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;tsweb/html&lt;/code&gt; function[2] takes a data structure that represents HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ clj -m web.core
&amp;lt;p&amp;gt;hello world&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can add inline css like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ clj -m web.core
&amp;lt;p style="color:red"&amp;gt;hello world&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Because we're using plain data structures for both HTML and CSS, we can use functional abstraction and other standard programming techniques instead of dealing with templating languages or preprocessors. (Hallelujah).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:div&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"goodnight moon"&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ clj -m web.core
&amp;lt;div&amp;gt;
  &amp;lt;p style="color:red"&amp;gt;hello world&amp;lt;/p&amp;gt;
  &amp;lt;p style="color:blue"&amp;gt;goodnight moon&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(Indentation added).&lt;/p&gt;

&lt;p&gt;Let's make this a little more complete, and let's have it write the HTML to a file for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:html&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:head&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:meta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:charset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;}]]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:body&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:div&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"goodnight moon"&lt;/span&gt;&lt;span class="p"&gt;)]]])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;-main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;spit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"public/index.html"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tsweb/html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before running this, you'll need to create the &lt;code&gt;public&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir public
$ clj -m web.core
$ cat public/index.html
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8" /&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;p style="color:red"&amp;gt;hello world&amp;lt;/p&amp;gt;
      &amp;lt;p style="color:blue"&amp;gt;goodnight moon&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can open &lt;code&gt;index.html&lt;/code&gt; in a web browser now.&lt;/p&gt;

&lt;p&gt;For interactivity, we'll add some plain Javascript. We could use Clojurescript, but it's overkill for simple things (in addition to increasing your payload size, using Clojurescript can be quite complex). You can switch to Clojurescript later when the time is right.&lt;/p&gt;

&lt;p&gt;Add a button to the div element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:div&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"goodnight moon"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:onclick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"alert(\"spam eggs\")"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"click me"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Regenerate the HTML and test out the button before we move on.&lt;/p&gt;

&lt;p&gt;Let's separate the Javascript into a separate file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:html&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:head&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:meta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:charset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;}]]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:body&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:div&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"goodnight moon"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:onclick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"doSomething()"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"click me"&lt;/span&gt;&lt;span class="p"&gt;]]]])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Create a file &lt;code&gt;myproject/public/index.js&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spam eggs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Regenerate and test it out.&lt;/p&gt;

&lt;p&gt;Next, let's add some &lt;a href="https://getbootstrap.com"&gt;Bootstrap&lt;/a&gt; to make CSS easier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bootstrap-4&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:rel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="no"&gt;:href&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="no"&gt;:integrity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="no"&gt;:crossorigin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;landing-page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:html&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:head&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:meta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:charset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:src&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;bootstrap-4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:body&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:div.container&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"red"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"goodnight moon"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:button.btn.btn-primary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:onclick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"doSomething()"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"click me"&lt;/span&gt;&lt;span class="p"&gt;]]]])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Boom. Now you're all set to make a sweet landing page for your new product/consulting business/dog. I'll let you finish that on your own, but you can take a look at the code for &lt;a href="https://github.com/jacobobryant/clj-landing-page-example"&gt;my startup's landing page&lt;/a&gt; for inspiration (yes, this whole document is just an advertisement). You can put the &lt;code&gt;public&lt;/code&gt; directory on any static website host. I use Firebase, but Github Pages and Netlify are other popular options.&lt;/p&gt;

&lt;h3&gt;
  
  
  The road ahead
&lt;/h3&gt;

&lt;p&gt;I'll write more in the future, but next you should learn about Clojurescript and Reagent. (Re-frame is also common, but don't worry about that for now). Reagent is a wrapper over React that lets you use the same syntax for HTML and CSS that we've used here.&lt;/p&gt;

&lt;p&gt;After that, it'll be time to get into backend development. I'll write about simple ways to get started with that, and I'll cover getting started with &lt;a href="https://www.datomic.com"&gt;Datomic&lt;/a&gt; as well, a database that embraces functional programming concepts (made by the creators of Clojure).&lt;/p&gt;

&lt;p&gt;I'll also give some tips for using the available Clojure tooling. For one thing, you should install the parinfer plugin for Atom (&lt;code&gt;apm install parinfer&lt;/code&gt;). With parinfer, you don't need to type any closing parentheses. Just indent your code properly, and parinfer will infer the parentheses for you.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Notes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;[1] I don't actually use Atom myself, but I recommend it here because it's a mouse-friendly editor that has working autoindent for Clojure out of the box.&lt;/p&gt;

&lt;p&gt;[2] &lt;a href="https://github.com/jacobobryant/trident"&gt;trident/staticweb&lt;/a&gt; is a simple library I've made that wraps &lt;a href="https://github.com/weavejester/hiccup"&gt;Hiccup&lt;/a&gt; and &lt;a href="https://github.com/noprompt/garden"&gt;Garden&lt;/a&gt;, allowing you to write inline CSS à la &lt;a href="https://reagent-project.github.io/"&gt;Reagent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;[3] This website is made with Hugo, but I've found it to be too inflexible. Eventually I'd like to do a rewrite with Clojure.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
