Walking through a nicely functional approach to the TicTacToe game for the Clojure study group.
Added a few changes to the original code I saw in the videos by Brian Wills to make the board and players easier to read.
Also make the play-game function the required arguments of board and player-sequence, so that the function explicitly uses arguments rather than shared values. Using arguments also means that play-game
can be called with different board states, this is useful for testing especially if a computer opponent was added as an option to the game play.
It would be cool to make an AI for both players and get the output from the game of two AI players shown. Would like to build a simulation like that seen at the end of the War Games movie, although this would look better as a web page rather than command line.
Added some more 4Clojure solutions
Got a Logitech MX Ergo trackball mouse today and it is so nice to use. It is a trackball, so the mouse itself stays static on the desk meaning I dont need to move my hand around and reducing RSI. It also means I dont need a lot of space to use the mouse either. The trackball is tilted so my hand is in more comfortable position, the same position I maintain with my tented Model01 keyboard.
Just noticed that def
supports a doctring, just like defn
. Adding a string after the name in the def
expression will be used as the docstring, assuming there is another value after the string (otherwise the name is just bound to the string).
I use , t a
to run all tests and the test report buffer will display in place of an existing buffer if the test buffer is not already showing. This is normal behaviour as I understand it. The test buffer should be the active window (has the cursor) so pressing q will quit the test report and show you the buffer that was in the window previously (eg. your repl). If you have the test report buffer shown in a window, then any new test report should always appear there.
If you find this behaviour not to your liking, you could look into Spacemacs Window Purpose layer to define a configuration to guide Emacs placement of windows (this is not something I have tried yet)
100 days of code challenge completed. Was it worth it? Well yes, it got me coding almost every day, and overall I certainly achieved more than 100 hours of coding, probably more like several 100 hours of coding. The only thing I didnt do was work on a specific project every day, but that would have felt like work and I enjoyed having a break from that routine.
Will I do a 100 days of code challenge again? Not sure, its quite a hard thing to be consistent with. I will certainly keep a developer journal from now on as it has been very useful.
Write up of the 4Clojure exercises I covered in yesterdays Clojure study group broadcast.
Popped out for a few essentials in the last day I am prepared to go shopping before the holidays :)
Continuing to write up a description on how I solved each 4Clojure exercise, explaining how I thought about the problem and different approaches possible.
Today was a write up and elaboration on the exercises I covered in yesterdays Clojure study group broadcast.
Walked through 4Clojure challenges number 16 to 22 in the Clojure virtual study group broadcast today.
Lots of fun with sequences and sequence related functions. Also included two exercises on defining your own functions.
Took Poppy to the vets for a checkup on her teeth, apart from a bit of plaque build up, they are fine. More teeth brushing for Poppy.
Cycled into Wagamama Southbank for another coaching session, getting my teeth stuck into 4Clojure challenge #53, a tricky one eventually solved with partition and partition-all.
Ouch, this was quite a tricky problem and very easy to get caught up in imperative thinking.
Trying to do this using loop/recur and reduce approach became very complex and we didnt get that working in the end.
I started a more functional approach along the right lines with partitioning up the data set so each combination of pairs could be compared to see if the second value was higher than the first. It took a bit of experiementing to realise I could also partition again using a function that grouped the pairs until the pairs stopped increasing. This second partitioning really put the data in to a shape that made it easy to process. Redundant data was removed and then the remaining partiions sorted by size (count
) and the largest continuous sequence found. Then the partitions just needed to be flattened to get the right shape of data as a result.
Planning activities for 2019, including ClojureBridge London events.
Another chance to read up about destructuring. Destructuring is a great way to reduce the amount of code you need to write by using pattern matching. We use destructuring to define local names from data structures, both in let
functions and function definitions.
The challenge itself was fairly straight forward, just demonstrating a nested destructuring example.
User feedback session for an interesting AI product. It was useful to hear from one of the users of the tool. However, a lot of distraction came from the team, especially in random discussions and discussions about how the tool should be used. This seemed a little about face, as we should be focusing more on how the user is working and fitting the tool around them. The more training we need to give to the users, the greater barrier there would be to adoption.
As I was travelling on the train, I carried on documenting the solution to 4Clojure exercises.
Team winter lunch with the team I will be working with in the new year. The venue was a very basic restaurant but with nice food. There are some interesting dynamics in the team, so will need to figure out how to work with them.
Some awkwardness from the team as most people were meeting for the first time. I asked lots of questions and tried to make connections…
Carried on adding to the 4Clojure repository of solution write-ups. Discussing challenge #49 Split a sequence.
There was a fairly easy solution using take and drop. However, with a little digging into the `clojure.core` the `juxt` function was a great way to show some abstraction over the drop and take.
Cycled into London today on the Brompton and my Tannus tyres still going strong. I finally got a moment to clean them too.
Another very productive coaching day in Wagamama today, covering the inside out approach to writing Clojure. I pushed 3 out of the 6 exercise we completed to Github.
Cycled over to SkillsMatter to give (finish writing) my Emacs for your digital life talk for Linux in London.
Covered several Easy level challenges
Discussed the thinking approach to solving 4Clojure challenges and problems in general. Breaking down problems into very simple parts, solving simple parts and then building them up to solve the larger problem. Much easier to spot errors and find code that does not quite work.
Challenges in 4Clojure seem to ask for quite specific forms of result, eg, you must return a set or a vector rather than a list. This can be a little distracting as many times its simply the values inside the form that are important and where the test is actually taking place. In extremely simplistic terms you can still think of all collections as a sequence, although everything but a list has extra symantics and features you can use.
Worked through challenges #46 to #51 during the coaching session.
Presentation for the Linux in London meetup group. Lots of festive cheer, swag and I even won a reusable tea cup!
The aim of the talk was to show off the advantages of Emacs, so I created my presentation using org-mode.
See ~/Documents/emacs-spacemacs.org
Extremely tired today.
Walking through the basic concepts of building a front-end website using ClojureScript and reagent, a react-style library.
Clojure Hack day was quite a small event however it gave us a chance to work on our own projects. Worked with Mani on some basic Clojure skills. Als worked on building a simple ClojureScript React style website with our primary school student (accompanied by her mom)
I also did a little more work with Scalable Vector Graphics, in the system monitor project I started a while ago.
SkillsMatter were kind enough to invite us to join in the event, however, there was some issue with food and SkillsMatter did initially exclude the Clojure group although eventually we were included in the event again.
Created a rough version of the CIDER logo using Clojure SVG (hiccup) sytax. Taking the HTML code for the logo, converted it to the Clojure SVG syntax.
Chasing references for my next potential employers
Quick write up about 4Clojure exercise #16 - Hello world.
Discussing the str
function to join values into a string.
Also covering how to write a simple function definition with fn
and call that function inline. For completeness, added the short form for a function definition using the reader macro #()
Considering my options for my next role. There have been a lot of really interesting roles I have interviewed for. There is one that seems to require the widest use of my skills.
Exploring the joining of maps and vectors into a map. Also explored some possible error conditions that can occur when using maps, such as incomplete pairs of keys and values.
A second meeting with Cervest, a very interesting data science company supported by Clojure tooling.
Also met with All Street Research who are looking to disrupt the financial industry and building systems in Clojure.
Did some 4Clojure on the train home.
A very simple challenge using conj to add values to a set.
A quick look at creating and extracting values from a map.
A lunch with a another company with Clojure roles, cycling to and from the meeting on the Bromptom. This time its Be-Social, a finance startup that is building an app to make spending money a more social activity and enabling friends and colleagues to share bills and other expenses.
Another 4Clojure challenge, this time #8 an introduction to sets.
A quick bit of coding to experiment a little with sets. A set in Clojure represents a unique set of values, the order is not guaranteed and is actually not important, its the uniqueness that is important. You could always pull the values out and sort them if you needed something with there.
The contains?
function is useful to return a boolean result as to if a value is within the set, or you can simply use the set as a function which returns the value if its present in the set or nil if not.
Another coaching session in Wagamama, very healthy and relaxing way to learn and teach Clojure.
Challenge #41 is quite a fun one. Looking at the first and last test of the challenge we are given a sequential set of numbers, so it seems you could just write a filter
function (or remove
) and a specific function to only return the right values.
The middle test uses keywords, so there is no uniform way of removing elements of the collection based on their value. So instead we have to do remove elements by position (so following the spirit of nth).
Once you discover the partition
function the problem becomes much easier to solve, as you can group the elements by their position in the collection. You can also step through a collection at a size different to the partition size you want to create. So with a partition of 2 and a step of 3 we can quickly get the shape of data we wanted. Then its just a case of tidying up the data to match the result using the flatten
function.
https://github.com/jr0cket/four-clojure/blob/master/src/four_clojure/041_drop_every_nth_item.clj
Collective approach to solving the day 9 challenge of the Advent of Code. There was a lot of discussion around what the challenge actually was and the different ways to solve it. There were possibly a few too many people in our group and although this did lead to some very interesting discussions, we didnt get around to actually solving the problem fully.
Two versions of the solution were added to the jr0cket/advent-of-code-2018 repository
Cleaned up the code from the first days Advent of Code challenge.
Mentoring my Clojure friend in the USA.
Inspired by the broadcasting by Tim Pote of his solutions to Advent of Code, I did my own spin of the first day of challenges.
A new Leiningen project created with the default template. Updated licence to Creative Commons.
lein new advent-of-code-2018
The first part of day one is a simple reduce +
over the specific data set of frequency adjustments. Added the unique data set for day one using a different namespace as its a long data set.
To see if there was any performance difference with using either apply or reduce functions, gathered timing and bench marking results using the advent of code data set. Results show that apply is faster in this instance.
Part two was tricky as we need to manage state while we process the frequency-changes. We need to keep track of the frequencies that we adjust the device to each time.
I tried out the imperative and mutable solution (DONT DO THIS AT HOME!) that Tim Pote discussed in his broadcast and it worked, although did not feel at all like Clojure.
Then I took a functional approach with recursion, using loop
and recur
at a pretty low level of abstraction. Again that worked, although the code is a little procedural and certainly not getting the most out of Clojure.
The design was evolved to using reduce and then further to use reductions to create all the intermediary results of the reduce. This made a pretty great abstraction on the design and a really simple expression. One thing that was missing was a function similar to distinct
except we wanted to keep just the duplicates, so a simple helper function was added.
Really impressed with the first day of live streaming advent of code by Tim Pote. Tim took the opportunity to not just solve the problem, but discuss the different ways to approach the problem in Clojure: recursion, reduction and sequence operators.
Created and advertise the virtual study group for this weekend.
Prepare Advent of Code challenges for the Virtual Study group on Saturday
Discussed the solutions to 4Clojure challenges 5, 6 and 7. Useful to remember that collection types are less important when comparing values as its the values inside those collections that are being compared. Often just returning a list or a vector makes no difference to the result.
Meeting with the founders of All Street Research, a very interesting Financial services company, developing Artificial Intelligence systems in Clojure.
Documenting some interesting 4Clojure challenges.
Described in detail the possible solutions to challenges 2 to 4.
https://github.com/jr0cket/four-clojure
Challenge 4 had an interesting sideline investigation of calling a keyword with arguments. Its assumed that calling the keyword :a has the same function signature as calling the function called keyword
. So when calling (:a :b :c)
the :b
argument is taken as a namespace and the :c
argument is the name of the keyword, which is then returned as the result.
Not a lot of energy today after 3 full days of events and 126km on the Brompton.
Started a repository for 4Clojure solutions, discussing the different ways they can be solved and any interesting approaches.
lein new four-clojure
Added solution and discussion around challenge #1 - Nothing but the truth
Everything ran much smoother today at the conference and I finally got my line-up for the panel.
Overall the conference went well. Unfortunately SkillsMatter mis-communicated that this was our biggest conference to date, this was incorrect as although we were well over 160 people, we did not break the 220 record from a few years ago.
All the videos from day one are already published on the SkillsMatter website and most of day two videos are there as well.
Had a great catch up with the speakers at the end of the day at the ‘speakers drinks and nibbles’ area. Some comments about this making the speakers a lot less accessible, which was obvious.
No time for coding today as I was exhausted after running the conference and cycling home.
Lots of small challenges to face today with the ClojureX conference, the most noticeable issue being the stage placement which blocked the view of the screen by the speaker for the audience on the left hand side.
Started day one of Advent of Code and completed the first part.
I like the Advent of Code challenges as they have a nice engaging story to read as you try solving the problem. For the first part of the first day I did spend more time reading the problem description though, as it turns out the answer was very simple.
In part one, it sets the scene that you are falling through time and space with only a little device to help stabalise you. The device needs to be tuned to a particular frequency, but you dont know what. So the challenge gives you 100 frequency adjustments, unique to your own login to Advent of Code. The first part of the challenge is simply to total all those values together.
To solve the problem, I copied all the numbers into a vector and added them all up using reduce +
.
At the Clojure workshop today for a Kafka and clojure.spec
workshop.
The kafka workshop showed us how to send information via a publisher and pull information from kafka using a consumer, all from within Clojure using the gregor library
The spec from the ground up workshop was a very detailed journey with lots of examples and exercises, for both defining and testing specs.
I organised a workshop the day before the ClojureX conference in London, to give a chance to work with Clojure developers outside of London.
There was a great turn out, especially as it was a Sunday. The venue provided by uSwitch was lovely, very posh and very comfy. It was just big enough for everyone and it was a very collaborative day.
Aleksandar ran an excellent Kafka session, first covering the essential theory, then diving into coding examples with Clojure driving Kafka producers and consumers. A Kafka instance was provided in a self-contained docker file and the code examples were on Github.
Deon ran a very detailed workshop on Clojure spec, the new library that provides a detailed and testable contract around you functions and data structures. Deon gave a brief introduction to Spec and then provided a series of challenges (in GitHub branches) to help us build up a series of different contracts and tests using spec. All the challenges and their solutions are on GitHub, in the spec from the ground up repository.
The fifth Clojure study group broadcast today was live coding a Test Driven Development approach to solving the Clacks encoder/decoder.
Also had another VR experience with Polybius on the PS4.
Broadcast a live coding session where the Test Driven Development approach was taken to write an encoder / decoder using the Clacks notation.
Clojure study group #5 broadcast
Spend a couple of hours coaching on hangouts today, guiding the installation of Spacemacs, enhancing the Clojure experience and how to start learning to use Vim-style editing. Added a Clojure Cheatsheet to the Practicalli Spacemacs book.
Learning Spacemacs does take a little time, as there are so many really useful features. To help focus the learning and not drown in features, I created a very terse cheatsheet to cover what I believe to be the absolute basics of using Spacemacs for Clojure development.
Updated week 5 of the Clojure study guide. For the fifth week we will do some Test Driven Development.
Catching up with the volunteers giving the Clojure workshops this week. Also confirming the venue is equipped with everything required. I will be taking some power extensions (20 sockets).
Suggested a topic for the ClojureX panel: Spreading the spirit of Clojure to the other conference organisers, along with some suggested people to have on the panel.
Starting to get into the Cider debugger which is a very simple to use tool to trace value changes as you step through a function call. This debugger is especially useful for iterative and recursive functions.
My .spacemacs
configuration file was a little messy, especially the dotspacemacs/user-config
section.
I moved all the older configuration sections and Emacs style custom keybindings to the bottom of the user-config section. Eventually these will all go once they are documented in the reference section of my Practicalli Spacemacs book.
Published the cleaned up version of the .spacemacs
configuration file to my Github gists.
CIDER includes a debugger that allows you to instrument a single function or all functions in a namespace.
, d b
instruments a function for debugging, creating breakpoints so you can step through each evaluation and value in the function when it is called.
Call the instrumented function as normal and a menu appears above the function definition.
n
steps the cursor through the function, showing the value of each symbol or expression evaluation in turn. You can step through the whole execution of the function or stop using q
.
Juraj Martinka has a nice video showing the cider debugger in action.
The also a fledgling project called Sayid that adds even more detailed debugging, however, the CIDER debugger is a really useful place to start debugging Clojure.
Wow, I just got a PS4 with VR headset and oh my is it emersive. I got the game Ploybuis from Llamasoft and it is amazing playing it just on the TV, but in VR it is unbelievably awesome. Watch the video on the website for just a small taste of how amazing this game is. Please do not watch the video if you suffer illness from strobing lights.
Also fitted my Beeline smart navigation device to the Brompton, so just need to get out of the house and try it. It has a decent sized display for a bike and shows you the general direction you are heading. Its linked to Strava and Google maps, so you can set a pre-defined route or you can set a destination and let the Beeline suggest turns you can talk along the route. Hopefully this is a bit less annoying than the Google maps voice directions updates when I take alternative turns than suggested.
Added some more content to the books.
Although we had a solution for the 4Clojure challenge 30, compressing a sequence, I felt there was a different approach using a function called partition
. So today I refactored the code and found a nice elegant alternative.
Created a much more elegant and idiomatic solution to 4Clojure #30, Compress a sequence challenge. Rather than try to iterate over the collection and only return the unique values, if you partition by identity then all values are grouped together, so you only need to take one of each to create the correct result.
Analyse the problem.
I thought that I could divide up the pattern as a way to identify duplicates. partition
by two creates pairs but doesnt help with identifying duplicates
(partition 2 [1 1 2 3 3 2 2 3])
;; => ((1 1) (2 3) (3 2) (2 3))
partition by 2, but only stepping through by 1 creates all the possible sequence of pairs its now easy to see the duplicates
(partition 2 1 [1 1 2 3 3 2 2 3])
;; => ((1 1) (1 2) (2 3) (3 3) (3 2) (2 2) (2 3))
so if we filter out the duplicates then we should be close
(filter
#(not= (first %) (second %))
(partition 2 1 [1 1 2 3 3 2 2 3]))
;; => ((1 2) (2 3) (3 2) (2 3))
The structure is not quite right, so lets flatten it
(flatten
(filter
#(not= (first %) (second %))
(partition 2 1 [1 1 2 3 3 2 2 3])))
;; => (1 2 2 3 3 2 2 3)
Oh, thats not right. It feels close, but how to merge correctly?
changing track a little lets use a variation of partition
called partition-by
and use the identity
function to create a sequence for each value
(partition-by identity [1 1 2 3 3 2 2 3])
;; => ((1 1) (2) (3 3) (2 2) (3))
Then we can get the first value from each sequence
(map
first
(partition-by identity [1 1 2 3 3 2 2 3]))
;; => (1 2 3 2 3)
This works for the vector of vectors test too
(map
first
(partition-by identity [[1 2] [1 2] [3 4] [1 2]]))
;; => ([1 2] [3 4] [1 2])
But it doesnt quite work for a string, but its so close
(map
first
(partition-by identity "Leeeeeerrroyyy"))
;; => (\L \e \r \o \y)
so it seems we need to treat the results slightly differently two results are a collection, one is a sequence of characters. If we test the result to see if it contains characters then we can post-process the result, reducing it to a string. So lets put the result of our partition into a local name then process the result if it contains chars.
((fn [pattern]
(let [compressed (map
first
(partition-by identity pattern))]
(if (char? (first compressed))
(reduce str compressed)
compressed)))
"Leeeeeerrroyyy")
;; => "Leroy"
Now try the function the the other two tests.
((fn [pattern]
(let [compressed (map
first
(partition-by identity pattern))]
(if (char? (first compressed))
(reduce str compressed)
compressed)))
[1 1 2 3 3 2 2 3])
;; => (1 2 3 2 3)
((fn [pattern]
(let [compressed (map
first
(partition-by identity pattern))]
(if (char? (first compressed))
(reduce str compressed)
compressed)))
[[1 2] [1 2] [3 4] [1 2]])
;; => ([1 2] [3 4] [1 2])
The test that uses a string type, also has a call to the result that will convert it from a sequence of characters into a string. So there is no need for a particular test for the type so we can simplify the result.
(fn [pattern]
(map first (partition-by identity pattern)))
Submitted answer to 4Clojure
(fn [pattern]
(map first (partition-by identity pattern)))
Face to face coaching in Wagamama today, covering some of the 4Clojure exercises
Went to the Thoughtworks Clojure dojo and worked on some more 4Clojure exercises. Got a bit entrenched in #30 Compress a sequence.
The 4Clojure challenge 30 is to compress a sequence with three tests.
http://www.4clojure.com/problem/30
Write a function which removes consecutive duplicates from a sequence.
(= (apply str (__ “Leeeeeerrroyyy”)) “Leroy”) (= (__ [1 1 2 3 3 2 2 3]) ‘(1 2 3 2 3)) (= (__ [[1 2] [1 2] [3 4] [1 2]]) ‘([1 2] [3 4] [1 2]))
(apply str ( #(reduce (fn [reslist listvalue]
(if (not= (last reslist) listvalue)
(conj reslist listvalue)
reslist))
[] %)
"Leeeeeerrroyyy"))
Ran the fourth virtual study group, discussing apps with maps as a way to think about how to model information with Clojure
Caught up with my friend in the east coast USA for some coaching. Today we looked at the Duct library from James Reeves. The nice thing about Duct is that it is very data focused. We got a duct website up an running from Spacemacs very easily, its just lein new duct project-name, open the source file in Spacemacs and then run cider-jack-in, ,'
***
Looked at defining data structures using Clojure maps (hash-map) which is a key-value pair data structure (like json but much more flexible in the type of content you can use as keys and values.
Discussed how to get information out of maps, using the get
and get-in
functions. Also showed that keywords and maps can be used as functions, which can sometimes be useful when writing short inline functions, eg. conditional functions with map
or filter
functions.
See the video: Clojure Study group #4 - working with data in Clojure hash-map
Attended the excellent London Java Community conference, which is an unconference style event. The event started with a talk from Simon Ritter on Java 11 whilst I worked with the other organisers to assemble the schedule from the talk suggestions. There was a great selection of talks which were grouped into the themes Architecture, AI & Machine Learning, Core Java, JVM languages, agile practices and self improvement.
I had the chance to broadcast two talks from the Conference, a lightning talk on broardcasting and a live Clojure hacking session called Clojure loves data
Created code examples for a Clojure talk at the LJC conference.
***
Its the LJC conference tomorrow, so I created some code examples to hack on for my talk. The talk will be walking through the code, evaluating it to show the results and discussing how Clojure takes a functional and data focused approach to design.
Second interview
London Clojurians meetup at Funding circle
Wrote a quick overview of the testing libraries and test runners available for Clojure.
Added a quick introduction into clojure.test
, to be expanded on soon.
The basics of working with hash-map collections, including techniques for iterating over the maps.
Create a quick overview of the libraries and test runners available for Clojure. Will extend this section in future to identify commonly used libraries and tools.
A simple introduction to testing with clojure.test, covering assertions, testing function, naming of test function and namespaces.
Clojure.test is the most commonly used test framework as it is shipped with Clojure already.
Today is the first job interview I have had for 15 months and only the fourth interview in the last 6 years, so will be interesting to see how prepared I am.
Turns out it was a great interview, I really enjoyed it. There are still a few more steps in the process, but a very good way to start and helps build my confidence.
More work on the code examples in the Clojure->Code repository to support the Practicalli Clojure book and a first draft of the chapter on Macros. There is much more I can add to the discussion of macros and how to write them, but for now its important to define when to use them and the constraints around their use.
Exercises from the ClojureBridge London workshop and a discussion on how those exercises were solved.
A brief explanation of macros and suggestions of where to use them.
Continuing to practice Clojure code by working through and organising my Clojure Through Code examples.
Examples of how to define a collection that represents the ascii codes for an alphabet.
Generating ascii codes given a starting reference.
Use of a for loop is not required as map can be used to join two collections together, in this case the collection that is the English language alphabet and the generated range of ascii characters.
The range of ascii characters is a sequential whole number series, starting from the given ascii code. So to generate the ascii number collection, range function is provided the start code value and a calculation of the end code value.
Various approaches to writing a palindrome checker.
More work on the Practicalli Clojure book, this time some thoughts on what to include for a core.async section.
Started a new section on core.async
Several example projects come to mind in order to explain how to use core.async
- Bike assembly line - some tasks can be done in parrallel, but not all
- Toy car assembly - summary of ideas from PurelyFunctional.tv
- Clacks messenger - visualise the Clack towers using the light patterns encoder-decoder code from earlier sections.
Coaching this evening, revisiting the Hoplon project but unfortunate it doesnt seem to run from CIDER. Not sure why its broken.
Discussed the libraries that have been moved into the clj-commons Github organisation and submitted an issue to add the Github pages link to the description of the clj-commons.github.io repository.
Discussed Finite state machines in Clojure and libraries that help define finite state machines. Finite state machines libraries include:
A new idea for a future coaching session is to try the Duct project for building a server side application and also use a Finite State Machine to model the UI. Inspiration comes from the blog: Restate your UI using state machines to simplify user interface development
More work on the Practicalli Clojure book.
Described with examples the common naming conventions used in Clojure.
Added Stuart Halloway’s 10 big ideas (although there are 11) as a way to think about the fundamental concepts that underpin Clojure.
Covering the syntax of the Clojure language with some relatively simple examples.
Third broadcast of the Clojure virtual study group, covering structural editing and the first 15 problems from 4Clojure.
Joined the Clojurians community on Zulip, an open source version of Slack. Zulip makes conversations more effective by adding the concept of topics to streams (streams are channels in Slack). Discussions within a Stream are all within a topic, helping focus those conversations and making it much easier to catch up with those conversations after they have happened.
I signed up to the clojurians.zulipchat.com community and I really like the UI, especially the concept of putting messages in a stream within a topic. Streams are channels in Slack. When you post a message in a stream, you supply a topic for the message. The message displays in chronological order in the stream, however clicking on the topic name in the left hand navigation, you can view only the messages for that topic.
Covered the basics of structural editing using Spacemacs.
Discussed the first 15 4Clojure problems and discussed how to help solve problems by looking at the `clojure.core` function documentation and source code.
Working on the Thinking Functionally section of the Practicalli Clojure book
Use Klipse to enable live example code for the Thinking Functionally section, allowing the reader to experiment with the code examples in the page.
Discussed the constructs available in Clojure for recursion, loop and recur, named function calling itself, map reduce etc, for
Added examples of these approaches to recursion.
Transducers are a very efficient way to transform data, especially complex transformations.
Applying for jobs today as well as being at the Redis Days conference. No time for code today. Day 62 - at RedisDay conference
Submitted Emacs talk to Linux In London community.
Still using Google docs for my CV as it generates a nice looking PDF file and I can always find the documents easily, regardless of which computer I am using (so long as there is Internet access).
Eventually I will write my CV in org-mode and get that to generate some really nice PDF and Latex output files. I can then keep everything on Github (although not sure about sharing this sort of thing publicly in case dodgy recruitment consultancies try and abuse it. I think that is low risk, but will think more about it.
Lots of interesting talks and some very interesting people to talk to.
Applied for a few jobs, mostly Clojure and one Developer Relations role.
Submitted Emacs talk to Linux In London community.
Updated the Practicalli Clojure book to use Version 3 of gitbook. Tweaked the styles to use a similar style to the improved ClojureBridge London styles.
Updated the book.json configuration of Gitbook to use version 3 and above.
Removed older plugins no longer used - exercises, quizzes, sunlight-highlighter.
Added plugins
- simpletabs - for tab sections with in a page, eg. for operating system specific instructions in the developer tools section
- youtube - adding embedded YouTube videos by just specifying the URL
- wide-page - set the page width to be wider (narrower margin either side of each page). This is very useful for larger and wide screen displays.
Ran gitbook install
to update the plugins in the Gitbook directory.
The ClojureBridge London workshop has been used to improve the style used by the Practicalli series of books. Bringing Practicalli Clojure in line with this style.
Expanded on the code created during the Coding dojo, detailing the design decisions that went into solving the problems.
4Clojure problem #18 can be easily solved by evaluating the filter expression in the REPL.
I describe how the filter function works and compare it to other functions that have related behaviour. This gives a more complete understanding of the filter function.
Analysis of the classic problem of generating the Fibonacci Sequence. The approach taken was to add the last two values of the sequence to create the next number, starting with a seed value of [1 1].
Detailed how the design was evolved using a simple loop recur iteration, showing the incremental changes in the design until an answer was found.
The local names in the code base were kept of reasonable size to be meaningful, but could have been converted to single characters to get a slightly lower golf score (although that isn’t important).
I like the 4Clojure problems where you have a restriction, as its a great opportunity to learn about the restricted function (or functions).
In this example, zipmap is restricted as it is the exact function that would solve the problem.
By looking at the implementation of zipmap and analysing the problem, a design was evolved that solved the challenge and helped us understand how zipmap works. This will be useful in understanding when to apply zipmap.
The incremental steps taken in this design show how conj and reduce functions can work together as well as how they can be substituted by the into function.
Started on the update process of the Practicalli Clojure book, there is a lot of work to do to get it where I want it to be.
Clojure dojo at uSwitch, working on some interesting 4Clojure challenges
Study guide is evolving, although covers the first few weeks specific sessions. There is also suggestions of topics to be covered in the future.
Included logos for YouTube Live broadcasts, hangouts and recorded broadcasts.
Using the content developed for ClojureBridge London the development tools section has been completely overhauled and should be much simpler to follow.
Moved the existing content to the end in case there is something extra that is worth factoring into the new content.
Writing the Spacemacs editor guide for ClojureBridge.
Updating the study plan for the Clojure Virtual Study Group (Virtualli Clojure? or just make it part of Practicalli).
Embed the YouTube video created previously on how to use the Clojure REPL in Spacemacs.
Described the actions in the video, along with the most used keybindings for starting a REPL, evaluating code and changing namespaces.
Added links to Spacemacs documentation and to Practicalli Spacemacs.
After a recent run through with a new student, some of the exercise descriptions seemed vague, as did some of the explanations in the answers.
Updated the time to numbers exercise in simple-values section Updated description of reading values from a sequence in collections section Updated average age of languages exercies in collections section
Broadcasting the second virtual study group for Clojure and created a logo for Live broadcasts and hangouts, using Inkscape.
Writing the editor guides for ClojureBridge London to describe what I did in the videos and provide a simple reference.
Arrange the plugins in alphabetically order within book.json making it easier to review.
A standard alphabetical order provides easier to use diffs when compared to the book.json configuration in Gitbook book projects I am developing.
Providing an embedded view of the YouTube video I created a couple of days ago.
Described how to start a Clojure REPL for ProtoREPL, the most common ways to evaluate code and changing to a different namespace.
Keybindings for ProtoREPL are provided as a quick reference.
Added images for MacOSX install, missing from the deployment guide commits.
I wanted to add a graphical image to the Virtual Study Guide section of Practicalli Clojure, so students could easy find the recordings, live broadcasts and hangout links.
In the spirit of broadcasting my work, I recorded a video of how I created the first logo using Inkscape and some images found on WikiMedia.
<iframe width=”560” height=”315” src=”https://www.youtube.com/embed/Ki7C17FPPnQ” frameborder=”0” allow=”accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture” allowfullscreen></iframe>
Preparing the ClojureBridge London exercises into the REPL in order to review them in the next hangout for MeetAMentor Clojure study group.
Finally figured out how to manage events and start hangouts in YouTube. Realised its not possible to change the type of streaming, so for now just using hangouts rather than my own streaming software. Will try Open Broadcaster System (OBS) at some point.
https://www.youtube.com/my_live_events
Click on the New live event button
Enter the basic info about the event
Once the event has been created, you cannot change the event Type (and there is no way to delete an event it seems)
In the Live Streaming events list, click the Start Hangouts On Air button. This opens the hangout but does not start broadcasting.
In the hangout popup window, click the person icon to get a link to join the hangout.
Only start broadcasting once you are ready, as once you stop the broadcast it cannot be started again.
Its DevRelCon London conference today and a chance to catch up with some friends in that community.
The award wining Joe Nash gave a great talk on how developers learn today, discussing why they are looking for a complete learning experience.
Developers have always been self learning, even if they went to University. Self-learning is a requirement for a developing your career and keeping things interesting. When learning you want a great experience and developers are investing in online courses and learning via video tutorials has seen a huge growth.
So what is a great experience?
The learning should connect
to the individual learner. They should know what they are going to learn, what they should know before they start learning (pre-requisites) and where to learn that. They should also gain a sense of mastery once they have finished the learning lesson, in that they know what they can do with their new skill. That skill should be clearly connected to the overall think you are trying to teach the developer.
Organise
content into easily digestible pieces that allow developers to learn specific aspects of the topic. Developers will learn at their own pace and can have quite different goals that are relevant. Each learning path should be self-contained in that it can be completed with a reasonable amount of effort, in a reasonable amount of time and without additional requirements (except the pre-requisites).
Developers learn by doing, so practice
is vital part of the learning tools. With online courses this practice should be built in and the most effective courses are learning by exercises. This practice should be tightly coupled with fast and relevant feeback to ensure that the developer is making progress. Without timely and useful feedback it is likely that a developer will get frustrated and either change what they are learning or move to another approach to learning (eg. if they are externally motivated to still learn)
Practice builds up confidence and moments to Reflect
help to cement the wider picture of all the things you have learnt. So exercises to pull from individual learning steps into a larger exercise can be valuable to demonstrate the big picture.
Created two videos showing the very basics of how to use editors for REPL driven development in Clojure, for Spacemacs and Atom & ProtoREPL
Feeling quite unwell most of today, so didnt get any time for coding
To make it easier for the attendees (and coaches) for ClojureBridge London, I’m creating minimal guides on how to use the recommended editors.
The guides are kept small so they do not overwhelm those new to coding and cover just the essential actions, opening a Clojure file / project, starting a REPL and evaluating code. I also included how to change to the namespace of a project, as editors typically start in the `user` namespace.
***
***
Getting creative with images and visuals today. As I have been creating more video content on my YouTube Channel, it was time for a visual update. So I fired up Inkscape and got creative.
In the past I have created some infographics as developer guides to Git and Heroku, to help people learn those tools.
Imagery, banners and logos for the Practicalli series of books and other communication channels where Clojure is taught by John Stevenson.
I am not a graphic designer, however, with the use of Inkscape and Scalable Vector Graphics, I can create some nice visualisations of information and themes.
## YouTube channel banner Practicalli Spacemacs playlist contains the all the videos created for the Practicalli Spacemacs book.
I have also started running a Clojure study group via the MeetAMentor community, using Hangouts On Air, which uses my Youtube account and imagery. So I have updated my YouTube banner from a nice picture of my cat, to a simple representation of the topics I cover in my channel.
YouTube can be viewed on different devices and each one is supposed to have a different size (although when actually testing this, it seems that YouTube uses pretty much the same part of the banner image regardless of media).
Initially I just created a design with the Logo’s, however, this felt a little too simplified and would not have said anything to those who didnt recognise the logos.
The design was refactored to place the names the logos represented under each logo. The font used was Ubuntu as its an elegant font to use. The colour of each name was taken from the predominant colour of the logo it describes. There was not much difference between the Green and Blue of the Clojure logo but Green seemed to work better for the text.
The finished banner design can be seen via the Imagery Design Github repository and on my YouTube channel.
On day 49 I published an article on REPL Driven Development and had some interesting comments, so I replied this morning.
Juraj Martinka left the following feedback: The idea of Design Journal sounds interesting. However, it seems there can be a lot of clutter eventually and that those examples can easily get out of sync. Do you really use this idea in your production code? How do other programmers/colleagues react to such code? Do you think it’s really the right medium for capturing design decisions (and ‘roads not taken’)?
My reply to Juraj’s feeback was:
A design journal is also talked about by Stuart Halloway in the “Running with Scissors talk” I believe and certainly in the apropos_cast podcast. It was good to hear I am not the only one doing this.
As I continually use these examples for further development of any code base and as REPL based tests for my understanding of what the code does, then the examples are always in sync. If something is part of a road not travelled, then it is documented so, at the point that it happens. Lazyness is for sequences, not developers :)
If sections become less relevant, it is an option to transfer these examples to a separate design document and simply include a link to the relevant section as a comment in the source code.
I dont consider the journal clutter, although this is quite a subjective point I agree. No one has raised this point when I used these technique until now, however, it is a good point that the design journal should be well written.
What code goes into production is defined by the team I work with, as yet though I havent come across any reasons why not to include this in what is shipped.
I would say the design journal is a very useful and interactive approach for capturing design decisions. What the right approach actually is will be up to the team working on the code base. I suggest this approach is more correct than not capturing these decisions at all.
Certainly this information could be moved into a design document, assuming the team were prepared to constantly update such a document. Literate programming design documents using Klipse or Org-mode babel would give live documentation that included an active repl, allowing you to get the feedback from code without having to switch back and forth between documentation and code editor (switching like this is one of the reasons documentation goes stale).
***
***
First MeetAMentor Clojure study group hangout went pretty well, although I had problems with YouTube initially as I couldnt open the YouTube website in Chrome.
*** repl.it clojure in 15 minutes
*** First MeetAMentor Clojure study group hangout
***
***
***
Assembling the Clojure study group content for the first week.
The first hangout will be used to give an overview of Cljoure, how its used by companies and a quick tour of the basic syntax.
Created an overview of the Clojure syntax, with some relatively simple Clojure code examples.
In the dojo this evening, one group hacked on Scalable Vector Graphics with Clojure, using my Tic-Tac-Toe game as a basis.
Added section suggesting Helm Transient state should you have many buffers to work on.
Tweaked the state Keybinding and the suggested Gnome keybinding on the Helm Transient State section.
Defined a curriculum for a Clojure Study Group, as part of the Meet A Mentor community.
Collected the Tannus tyres for my Brompton bike and fitted them ready for riding to the Clojure dojo tomorrow at Thoughtworks.
Some more hacking on Spacemacs book.
I suggest the followng schedule for the Clojure study group and would appreciate your feedback, especially as to the topics and level of the plan. Start date is either 3rd or Sunday 4th November (based on your feedback)
Week1: Overview of Clojure - covers the syntax, a few common functions, how to start learning Clojure and REPL driven development. Homework: practice writing some simple Clojure.
Week2: Tooling and practising - briefly covers the different editors that give a good Clojure experience, resources for practising Clojure (4Clojure, Exorcism, CodeWars). Homework: some 4Clojure exercises
Week3: Data Structures and Immutability - understanding how to model the world with immutable data (values) Homework: writing a simple encoder/decoder challenge and more 4Clojure exercises
Week4-8: Thinking Functionally - writing your own (pure) functions, using sequences, lisp comprehension, higher order functions, functional composition. Homework: various small challenges and 4Clojure exercises.
If there is interest, we can also start a project to build a web application in Clojure (or a full stack app with Clojure/ClojureScript) at any point after the first week.
SPC g b
opens a buffer showing the commit history of the current file, by author of each commit.
RET
will show the details of the commit under the cursor.
Stocking up on healthy food for the winter and Brexit fallout. Ordered lots of chickpeas, soyabeans, mung beans, butter beans, black rice, apricots, dates, and spices to make sauces with.
Then hacked on the Spacemacs book some more.
Described two methods of highlighting changes, fringe and smeargle.
Updated the section names in Magit for clarity
Added `g r` keybinding to refresh the magit status buffer.
Some quick hacking on the Spacemacs book
Update: Vim tips for developers & Speaking Vim
Moved the more-vim section to vim-tips-for-developers, defining keybindings and tips specifically useful for working with code.
Added surround to speaking-vim action section and put actions, modifiers and text objects in alphabetical order to make them easier to learn.
Noticed the Inspector was using the M-RET
keybinding form, rather than SPC
.
A tweet by Martin … who created Clojureverse let me know about OpenCollective, a way to fund open source and community based organisations. So I set up an OpenCollective for London Clojurians.
***
Refactor the grouping of keybindings and tips into a logical order, to make them easier to discover and hopefully learn. This curating of Vim keybindings and tips will be put into a video (or small series) on getting the most out of Vim style editing in Emacs.
Used Precursor app to create a simple sketch of the Status Monitor app I am building. Precursor is a collaborative sketch tool that feels very modern and looks great, its also pretty easy to use. I would still use Inkscape for infograms, developer guides and other single page graphics as there are many more features, however, Precusor seems much more effective for sketching out ideas and of course collaborating in real time.
Precursor is also written in ClojureScript and there was a short but interesting article from its author about ClojureScript as a product design tool.
Created a London-Clojurians meetup on OpenCollective as a first step to providing a facility for people and companies to donate to the London Clojurians community.
A budget has been added of $300 to cover basic expenses for the year, which breaks down as Meetup.com expenses and stickers for LondonClojurians and ClojureBridge.
I had a few issues with the Internet connection today, so I created some short screencasts on using Spacemacs. I am back on line and the videos are being uploaded. I am getting more comfortable doing short videos without the need for a lot of preparation. When ever I see a situation that suits a video, I make one (and avoid pontificating about it).
Added to the Spacemacs book, an overview of the Sayid debugger and Vim tips for Clojure developers, especially around simulation of basic structured editing using surround.
- Spacemacs Yasnippet for boilerplate code and often repeated text
- Spacemacs narrowing and iedit magic
Coaching a new student today using the ClojureBridge workshop. Just an hour for the first session in which I gave an overview of Clojure and supported them through some simple exercises.
Testing out how well org-mode images display when pushed to Github.
Discovered SPC n +
and SPC n -
to increment and decrement numbers. When creating a new journal entry I copy from a previous day and paste it as the current day so I have the same structure (I should use a snippet instead). To update today’s entry from day 39 to day 40, rather than changing the word with cw
and typing in 40, I jumped to 39 (SPC j j 9
) and used SPC n +
to update the number.
Refactored the descriptions for the challenges to remove some ambiguity
I am using more images in the log so its handy to see them displayed rather than just as links.
, T i
will toggle the display of images in Spacemacs
. i l
pops up a prompt to create link from either a web address or a local file name, followed by a prompt for the link text. Selecting text before calling org-insert-link
will use that as the default link text.
Any previously used links will be remembered and presented in a helm list, so you can easily narrow down to the link you wish.
The att_org
attribute can be used to add meta data to your image, including the :width
or :height
of an image.
So if an image is 400 pixels but is too small, you could set the display size for the image to 80 pixels using #+attr_org: :width 800
It will be interesting to see if the meta data is picked up by Github when it renders the orgmode file.
If the attr_org
does not work then there is also attr_html
which I assume is used when exporting an org-mode file to HTML.
Looking at some Hiccup tips to improve the way I use the library. Adding a better look to the Status monitor front page with some Bootstrap magic.
Hiccup is a very easy to use library and I find it so much better than writing HTML directly. As Hiccup is defined as a data structure it is very easy to edit and manipulate using the structured editing tools that come with Clojure editors. As Hiccup is just data structures its also easy to generate them with Clojure code.
The Hiccup library API is clearly defined, the documentation could do with examples though. Luckily the Internet has lots of examples. There is also a selection of Hiccup tips from PurelyFunctional.tv.
Updated the form to use BootStrap to make it more usable and have a better aesthetic.
Although Hiccup is a little short on examples, it is generating HTML so its fairly easy to figure out what needs to be created. This holds true for Bootstrap too. Much of the time its a simple case of just adding the right style in the right place. Styles are just a map so its easy enough to just copy the name from Bootstrap documentation and add that style to your tags.
Just using a simple form works okay, but doesnt look very nice.
By adding some Bootstrap styles, the page looks a lot better. Simple drop-down form in bootstrap
Inside the form I added a div
with the style form-group
as there are multiple form elements, a label and a select (drop-down).
The button is using the hiccup.form/submit-button
function with the style btn-outline-primary
applied. Without the form-group
div there would not be any space between the button and the select drop-down.
[:body
;; An invisible container to create a default margin at each side of the web page
[:div {:class "container"}
;; Page Header using a large central banner, called a Jumbotron
[:div {:class "jumbotron"}
[:h1 "Mock Status Monitor Dashboard"]]
;; Key systems to monitor displayed in a single bootstrap row, with 3 columns.
[:div {:class "row"}
[:div {:class "col-md-12"}
[:h2 "ACME Infrastructure Locations"]
[:form {:action "/dashboard"}
[:div {:class "form-group"}
[:label "Choose data centre location to view"]
[:select {:class "form-control"}
(for [location data-centre-locations]
[:option {:value (:name location)} (:name location)])]]
(web-form/submit-button {:class "btn btn-outline-primary" :name "submit"} "View Dashboard")
]]]
] ;; End of :div container
] ;; End of :body
As I updated the resulting page from the /
route, then I updated the tests to reflect the new content. I also remembered to run the tests before committing and pushing to CircleCI. My build is now passing on CircleCI, yay!
Add tests to check for body title and that the page includes Bootstrap style sheets and a Jumbotron.
These tests are more about how to write tests than what should be tested, so may be a little brittle.
Organising ClojureX free workshops for the 2nd December. We have an clojure.spec
from the ground up confirmed and I am planning on giving an intro to Clojure CLI and figwheel.main for building (and testing) ClojureScript applications. This would be based on the Figwheel Tutorial.
Reached out to ClojureBridge Bilbao chapter today and offered to mentor them through their first event, https://www.magnet.coop/clojure-bridge-bilbao.
Started planning ClojureBridge London events for 2019, the first hopefully at the end of January or early February and the second event for mid-May.
Worked on the Status monitor, adding a simple drop-down and then form to select a specific data centre location.
A basic welcome page for the default route, /. Welcome pages is an hiccup html5 page that uses bootstrap for style.
Using hiccup drop-down
function I hard coded a drop-down component with two locations for data centres.
[:div {:class "jumbotron"}
[:h1 "Mock Status Monitor Dashboard"]]
;; Key systems to monitor displayed in a single bootstrap row, with 3 columns.
[:div {:class "row"}
[:div {:class "col-md-12"}
[:h2 "ACME Infrastructure Locations"]
(web-form/drop-down ["London" "New York"] ["London" "New York"]) ]]
Changed the hard coded drop down to be a generated form. Defined a collection of data centre locations to generate the form from.
;; Data centre locations
(def data-centre-locations
[{:name "London" :latitude 42 :longtitude 24}
{:name "New York" :latitude 42 :longtitude 24}
{:name "Singapore" :latitude 42 :longtitude 24}])
;; Main page for application
[:div {:class "row"}
[:div {:class "col-md-12"}
[:h2 "ACME Infrastructure Locations"]
(web-form/drop-down ["London" "New York"] ["London" "New York"]) ]]
[:form {:action "/dashboard"}
[:td
[:select
(for [location data-centre-locations]
[:option {:value (:name location)} (:name location)])]
[:input {:type "submit"} "Monitor Location"]]]]]
Finally fixed the build on the Status Monitor app and continued to work on the SVG library.
Added beginner friendly issues to the ClojureBridge London task board, specifically to write a simple user guide for the most common Clojure editors.
Asked Alexa to “play classical music” and it was pretty good mixture. I discovered I can also ask Alexa what the name of the song is that is currently playing (handy when I am in the flow of typing). I switched to rock music when I started feeling sleepy.
I left some experimental code in the previous commit without putting into a comment. After breaking the build twice, I should look at automating the running of tests locally. It has given me a reason to go and look at the clojure.core.spec.alpha specifications.
Required libraries should be given a contextually meaningful name as an alias, helping to identify the purpose of functions defined outside of the namespace.
Giving meaningful context helps code to be understood by any person reading the code. It is also easier to search for usage of functions from that context in the current project.
Aliases are rarely typed more than once in full as Clojure editors have auto-complete, so there is no benefit to short of single character aliases.
(ns status-monitor.handler
(:require [hiccup.page :refer :as web-page]
[hiccup.form :refer :as web-form]))
In very commonly used libraries or very highly used functions through out the code, refer those functions explicitly
(ns naming.is.hard
(:require [compojure.core :refer [defroutes GET POST]]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
The compojure template required the compojure.core library by referring all functions from that namespace. While this does give convienience of just using the function name without a namespace, it does mean many functions not used are included.
(ns status-monitor.handler
(:require [compojure.core :refer :all]))
Using this form also raises a warning from the Joker linting tool that I have running in Spacemacs.
To be more specific when using the compojure.core library, I changed the require to refer the specific functions / macros used, defroutes and GET
(ns status-monitor.handler
(:require [compojure.core :refer [defroutes GET]]))
Stating exactly which functions you are using from each library helps with maintaining the code as well as minimising unknown conflicts.
Changed requires for hiccup.page
and hiccup.form
to use a specific alias name, rather than using :refer :all
Thinking of the intent of each library, I chose the following alias names
[hiccup.page :refer :as web-page]
[hiccup.form :refer :as web-form]
The monitor-dashboard function was updated to use the new alias on functions from these two libraries.
No functions are actually used from hiccup.core, it only includes html
and h
anyway, so the hiccup.core
require has been removed.
In my eagerness to update the hiccup libraries with a meaningful alias, I forgot to remove the :refer
directive. I also forgot to run the tests before committing the change. So when I pushed the commit to Github, I got the following error from CircleCI.
The most interesting parts of the error message were these two lines showing that clojure.alpha.spec
library is being used to test namespace definitions:
Exception in thread "main" clojure.lang.ExceptionInfo: Call to clojure.core/ns did not conform to spec: fails spec: :clojure.core.specs.alpha/ns-form at: [:args] predicate: (cat :docstring (? string?) :attr-map (? map?) :clauses :clojure.core.specs.alpha/ns-clauses),
The ns-clauses
specification is define in clojure.alpha.spec
as
(s/def ::ns-clauses
(s/* (s/alt :refer-clojure ::ns-refer-clojure
:require ::ns-require
:import ::ns-import
:use ::ns-use
:refer ::ns-refer
:load ::ns-load
:gen-class ::ns-gen-class)))
The ns-clauses
spec looks for the :require
keyword and compares its value to the spec for ::ns-require
which is defined ass
(s/def ::ns-require
(s/spec (s/cat :clause #{:require}
:body (s/+ (s/alt :libspec ::libspec
:prefix-list ::prefix-list
:flag #{:reload :reload-all :verbose})))))
The ::ns-require
checks for a library name using :libspec
which is defined by the spec ::libspec
(s/def ::libspec
(s/alt :lib simple-symbol?
:lib+opts (s/spec (s/cat :lib simple-symbol?
:options (s/keys* :opt-un [::as ::refer])))))
This is where I believe the error is being detected as I was using both ::as
and ::refer
in my namespace definition.
The full error message was reported in CircleCI status-monitor build #13, which I formatted for easier reading:
Exception in thread "main" clojure.lang.ExceptionInfo: Call to clojure.core/ns did not conform to spec: In: [1] val: ((:require [compojure.core :refer [defroutes GET]] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]] [hiccup.page :refer :as web-page] [hiccup.form :refer :as web-form] [status-monitor.svg-components :as svg-components])) fails spec: :clojure.core.specs.alpha/ns-form at: [:args] predicate: (cat :docstring (? string?) :attr-map (? map?) :clauses :clojure.core.specs.alpha/ns-clauses), Extra input #:clojure.spec.alpha {:problems [{:path [:args], :reason "Extra input", :pred (clojure.spec.alpha/cat :docstring (clojure.spec.alpha/? clojure.core/string?) :attr-map (clojure.spec.alpha/? clojure.core/map?) :clauses :clojure.core.specs.alpha/ns-clauses), :val ((:require [compojure.core :refer [defroutes GET]] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]] [hiccup.page :refer :as web-page] [hiccup.form :refer :as web-form] [status-monitor.svg-components :as svg-components])), :via [:clojure.core.specs.alpha/ns-form], :in [1]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x4565a70a "clojure.spec.alpha$regex_spec_impl$reify__2436@4565a70a"], :value (status-monitor.handler (:require [compojure.core :refer [defroutes GET]] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]] [hiccup.page :refer :as web-page] [hiccup.form :refer :as web-form] [status-monitor.svg-components :as svg-components])), :args (status-monitor.handler (:require [compojure.core :refer [defroutes GET]] [compojure.route :as route] [ring.middleware.defaults :refer [wrap-defaults site-defaults]] [hiccup.page :refer :as web-page] [hiccup.form :refer :as web-form] [status-monitor.svg-components :as svg-components]))}, compiling:(status_monitor/handler.clj:1:1)
Joined the People’s Vote march today and it was huge, one of the biggest gathering of people I have ever experienced. Over 700,000 people as a rough estimate on the day, however, it felt like more than 1 million people. It took around 4 hours for everyone to make it from Park Lane to Parliament Square, which is normally a 30 minute stroll. It was a wonderful day and everyone was very supportive and friendly. It restored my faith in humanity and wiped away the depression that Brexit had induced in me.
I did some coding on the ClojureBridge User Guide for Spacemacs.
***
How do you break out of an iteration in Clojure, when you are iterating over a large data set and you realise you no longer want the results.
I had a play with my Clojure Through Code examples and experimented with a Palindrome checker.
***
Today is Cosmic Cuttlefish day, the release of Ubuntu 18.10. I’ve been using Ubuntu 18.10 and its pretty snappy as a desktop and uses less memory. Will wait a few weeks before updating my main laptop.
I created two more videos for the Practicalli Spacemacs playlist on my YouTube channel. One on using Magit to easily try out pull requests, the other to delete multiple buffers easily with Helm transient state.
I had a look at https://github.com/Unrepl/spiral, an Emacs Clojure IDE that uses Socket REPL via UNREPL protocol. It has some nice usability concepts that are shown on the project page. Its sill a young project, so wont replace CIDER for me at the moment. There has been a discussion about merging this work into CIDER though. There is also the ultimate guide to REPLs that is an interesting read.
Trying out the Ubuntu theme for Spacemacs. It looks pretty good, although I might want to tone down some of the colours and make them a little darker.
Spacemacs Ubuntu theme - org-mode link example
I’ve started using Helm Transient state menu more often, opening with M-SPC
when you have a helm popup open. I find the transient state useful for navigating through the list with just j
and k
. However, the transient state menu is really great for running actions over multiple files. Combining the pattern based searching with marking files (T
marks all files listed for a particular pattern) makes it really easy to kill lots of Magit buffers that never seem to close properly.
I created a quick 2 minute 30 second video on Helm Transient State for killing multiple buffers easily.
Created a video to demonstrate how easy it is to use Helm Transient State to kill multiple buffers of a particular type. In this case removing several magit buffers that didnt close when I used q to quit magit.
Magit git client provides an easy way to try out pull requests shared on remote repositories.
Open a file from a project and press SPC g s
to open Magic.
b y
will popup the current list of pull request from the git project. Selecting a pull request will open git a local branch for that pull request. You can now test all the changes you wish.
Once you are done, you can go back to magit with SPC g s
and change back to your previous local branch with b b
.
So Magit provides a quick and simple way to collaborate with other developers.
To use Magit with Spacemacs, simply add the git layer to your .spacemacs layer configuration.
https://practicalli.github.io/spacemacs/magit/
I created a quick video of how to use Magit to easily try out pull requests and published it to my Practicalli Spacemacs playlist.
Added a section on using Magit to checkout a new branch that is a pull request on a remote repository (i.e. Github).
Embedded a video from YouTube showing this in action.
As I’ve been updating the content in the ClojureBridge London workshop, it needed some more style to make sections stand out further.
I also added the install guide for Spacemacs, including Emacs of course, for Linux, MacOSX and Windows.
More updates on ClojureBridge London workshop
Some of the content did not stand out very well, especially inline code and code blocks. Added website.css styles to make the code stand out.
Added the wide-page plugin to spread the content wider on the page, so it looks better on a higher resolution monitor. The plugin has a maximum width of 95% which was a bit high, but it was easy to over-ride this by adding a style to the website.css file. A width of 72% looks good and will seek further feedback on this.
Wrote simple install instructions for 64bit Emacs, minimum version 25 and installing Spacemacs.
Hacking on Clojure examples as a break from ClojureBridge London.
Hacking on some examples for my Clojure through code repository, to be used for my Practicalli Clojure book
Using the Criterium library to measure the performance of expressions in Clojure. Very useful for analysing parts of your code to see how quick they are to run.
Modelling a combination lock and calculating all the possible combinations. Then adding a constraint that no combination should contain the same numbers, eg. discard 1,1,1 and 1,1,2, etc.
An example of the power of clojure.core.match to solve the classic fizzbuzz game.
The classic fizzbuzz game were you substitute any number cleanly divisible by 3 with fix and any number cleanly divisible by 5 with buzz.
If the number is cleanly divisible by 3 & 5 then substitute fizzbuzz.
Using the require function we include the library ~clojure.core.match~ (match may seem similar to a case statement from other languages). We use match to compare the two results returned from the modulus functions.
(require '[clojure.core.match :refer [match]])
(defn fizzbuzz
[number]
(match [(mod number 3) (mod number 5)]
[0 0] :fizzbuzz
[0 _] :fizz
[_ 0] :buzz
:else number))
This is an example of a simple pattern matching problem.
First we calculate the modulus of the number given as an argument by 3 then the same number by 5. If the modulus value is 0 then the number is divisible exactly without remainder. The result of these two function calls are the elements of a vector.
There are 3 possible patterns to match against, each returns the appropriate value (fizz, buzz, or fizzbuzz). If there is no match, then the original number is returned. The underscore character, _
, means that any number will match in that position.
Now we can call fizbuzz for a specfic number
(fizzbuzz 1)
(fizzbuzz 3)
(fizzbuzz 4)
(fizzbuzz 15)
If we want to convert a sequence of numbers, then we can call fizzbuzz over a collection (eg, a vector) of numbers using the map function
(map fizzbuzz [1 2 3 4 5])
We can make a function called play-fizzbuzz
to make it easy to use
The function takes the highest number in the range and generates all the numbers from 0 to that number. Finally, we convert the results into strings
(defn play-fizbuzz [max-number]
(->> (range max-number)
(map fizzbuzz)
(map str)))
;; Now, lets call our play-fizzbuzz function with the highest number in the range of numbers we want to play fizzbuzz on.
(play-fizbuzz 30)
More work on the ClojureBridge install guides (as I am on a roll).
Lots of changes to the development environment section of the ClojureBridge London workshop.
Changed files to consistent naming convention
Added comments to each section to make changes easier to do by specifically highlighting each operating system section.
Updated the installation instructions to use OpenJDK 8 where possible.
Used simpletabs plugin to create a separate tab for each operating system.
Added operating system sections via simpletabs plugin
Added more install options, including GitBash for windows
Moved the checking of the install to the bottom of the page
Changed the install guide list into a table for each of the common tools (Java, Leiningen, Git).
Added brief overview of each editor to start students thinking about which editor they may want to use.
A wet day is a good day to focus when working at home.
Started a new coaching relationship today with an experienced Python developer. Had a great first catchup over hangouts and defined some tasks to work on.
Testing a pull request to make the REPL and REPL history buffers a better experience - still some work required.
Testing #11431 pull request
Trying out a pull request as a branch is really easy to do thanks to Magit.
Open a file from the Spacemacs repository, eg .emacs.d/README.org
.
Open Magit status, SPC g s
b
opens the branch menu
y
opens a branch from a pull request, prompting you for the URL.
And that is it. As this commit contains elisp changes, then I can go and evaluate the code in a buffer, or restart Spacemacs to pick up the changes. I should create a screen cast for this.
Some more hacking around with a pull request for the Spacemacs Clojure layer, improving the Vim Experience for the Clojure REPL and REPL history buffers. Both these buffers are configured only for Vim Insert or Emacs states, not usable in Vim normal state. This is unfortunate at both these buffers open in Vim normal state, so you have to change state before doing anything
Trying out #11431 pull request I noticed that RET
is not working in the REPL buffer. Including n
and p
navigation in the pull request is really needed in the REPL History buffer, to navigate between expressions, along with replicating the existing vim insert keybindings.
I opened a Clojure source file and started the REPL. I opened the REPL buffer with , s s
. Whilst still in Vim normal mode I used , P
to open a buffer with the REPL history. That all works very well.
I cant jump to each expression (as you can with n
and p
in vim insert mode). However, I can press RET
to send the current expression to the REPL buffer and close the REPL history.
With the cursor back in the REPL buffer in Vim normal mode, RET
doesnt make the expression evaluate in the REPL buffer, it does nothing. If I switch to Vim insert, i
, then of course I can evaluate the expression. I’ve tried a few examples and it seems something is missing.
I found an example of multi-line editing in the REPL in the #emacs channel, so considering a pull request that does the equivalent of this, but defined in the usual keybinding form in the Clojure layer. RET
creates new lines and indents, C-RET
evaluates the expression. This works the same way in other tools, eg. Atom, VSCode, LightTable, rebelreadline, etc
(define-key cider-repl-mode-map (kbd "RET") #'cider-repl-newline-and-indent)
(define-key cider-repl-mode-map (kbd "C-<return>") #'cider-repl-return)~~~
Perhaps a :variable
can be added to the Clojure layer to allow configuration of a single or multi-line REPL buffer.
I havent used the REPL history buffer feature much in Spacemacs and today I remembered why. It works great for Emacs state, but doesnt work well for Evil as you have to switch from Vim normal to Vim insert states to do anything.
Luckily someone has started working on a pull request to address this.
I realised the book was a bit out of date regarding the REPL history and history buffer, so gave it a quick update.
Added table of keybindings for scrolling backwards and forwards through the REPL buffer history to my personal config, .spacemacs
.
Changed keybinding documentation to use unicode arrow keys. Added specific keybindings and commands for working with the cider-repl-history popup buffer.
A new pull request for the Spacemacs Clojure layer was added today, #11431 Clojure enhancements
- add a keybinding to open the cider repl history buffer in an evil way
- evilfy
cider-repl-history-mode-map
- allow to send input to a cider repl in normal mode with
RET
To summarise the pull reqest, , P
in Vim normal mode in the repl buffer leader would open the repl-history buffer. RET
would send the current expression under the cursor to the REPL and close the REPL history buffer. RET
in the REPL buffer in Vim Normal mode would evaluate the current expression (without having to go into vim insert state).
Having experimented with the repl-history it is definitely confusing to have to switch to vim insert mode to call the buffer history and again switch to vim insert. I would like to have SPC s h
keybinding that opens a buffer with repl history in vim normal mode, which i can navigate quickly between each expression in that history and press RET
to push that expression back into the REPL buffer for bonus points you could evaluate the expression just pushed without having to go into vim insert mode.
It would be nice to have different keybindings, one that quits the history after you send the expression (so this is what SPC
or RET
currently does in vim insert mode), the other vim insert keybindnigs keep the repl history open.
RET
is for vim normal mode, so you can evaluate an expression in the repl buffer without having to go into vim normal mode.
My own preference for a REPL history keybinding would be , s h
for major-mode > cider > history
. I am not sure how P
means history in a mnemonic way, unless it is for Previous? If P is used in cider itself, then I am okay with that. For a top level keybinding for REPL history a meaningful symbol could be used, as is used to start the repl. So you could have , s h
and , <
which both call the repl-history
, s h
avoids switching to the repl buffer first to get to the history and especially if somebody would want to eval form again
In cider it is C-c M-p
, but this does not fit the mnemonic menu system. , s h
and , <
fits into the existing Spacemacs keybindings and mnemonic menu approach. I would be interested to hear from others as to what they prefer.
Spacemacs Clojure layer related issues:
syl20bnr/spacemacs#4124
#4124 Support Emacs lisp keybindings in Clojure mode
Emacs lisp has some useful keybindings like “go to end of line and evaluate last sexp” that are absent from the Clojure mode keybindings.
Clojure, Enhancement
If I didnt use Spacemacs, what editor would I use. I havent found a more suitable environment for myself yet, but as I document tools for ClojureBridge London, then hopefully I will have a better view.
I am still trying to decide which tools I like for Clojure development, other than Spacemacs of course.
Atom.io and ProtoREPL are pretty polished, however, the keybindings for ProtoREPL are more complicated than Emacs. Using Proto-mode with ProtoREPL gives more sensible keybindings as it gives a Vim multi-modal editing experience and a Spacemacs style menu. The Proton menu seems to have the basics, but there are some things that could be added (que a pull request, as proton is written in ClojureScript after all).
VisualStudio Code is a pretty slick editor and Calva is the best of several extensions to support Clojure development. I just find VSCode a little tricky to use as I havent read the user guide properly I guess. I would prefer if Calva started a REPL from within VSCode, rather than starting one outside and connect, although it works well. There are Vim extensions for Code too.
I should be able to get a better handle on ProtoREPL and Calva as I put together a simple user guide for ClojureBridge London workshop.
Added a distinct Friday section to make it easier to see that the workshop has content for both Friday evening and Saturday.
Created a new install guide for VSCode and Calva extension, using new tabbed format to separate the Operating System specific information.
Updated the ProtoREPL install guide with details on how to configure with Leiningen, which is an important step in the ProtoREPL setup.
I found a nice plugin for Gitbook to have a tabbed section in a page, improving the presentation of a single install page for each of the tools. Any differences in approach, e.g. installing on a particular operating system, can be put in their own tab. It probably shows my bias that I put Ubuntu Linux as the default tab (oops).
Had a catchup with a company interested in getting involved more in the London Clojurians community. We discussed the ClojureBridge London event and other activities that the community does. Now have two ClojureBridge London events in planning for 2019.
Assisting a couple of speakers with their talk titles and descriptions for the ClojureX conference this year. Almost everyone is published on the schedule now.
I will be coaching a new person this weekend, just arranging the details and starting to set expectations.
Updated to use the simple tabs plugin to provide a simple way to separate the unique install steps for each operating system.
Added installation instructions for all operating systems.
Added details on how to run and test the installation.
A plugin for adding tabbed sections in a page, useful for separating out specific details in a wider article.
This plugin will be used for the development environment section.
It is great to hear from people reading your books, blogs, etc. I received some very warm feedback today from a developer who is interested in learning Clojure and is really enjoying my practicalli books. This is great to hear and really helps motivate me to finish those books.
Continued working on the Spacemacs book, organising the debugging section a little better. Added details of how to run Magit in full frame, which I find much easier to work with changes.
Also worked on the development tools install guides for ClojureBridge London. Although we have Klipse REPL built into the workshop material, it doesnt save any work. Obviously Klipse is also not going to be the follow on editor that the students use, so we use the Friday evening of the event installing a Clojure aware editor. The editor tends to be one of Atom.io, VisualStudio Code, Emacs (yes, we have had several students using Emacs, mostly with a Spacemacs setup). Some students that are studying Java are using Intellij, so we also help with installing Cursive.
Added quick reference section for adding unicode characters
Mainly using unicode characters in the content of my books/guides to represent keyboard characters, such as arrow keys. It is assumed that these unicode characters make the keybindings easier to understand.
I started on using Atom and ProtoREPL for Clojure development when I was coaching a developer who wanted to learn some Clojure. Although I had published the content a while ago, I realised I had not pushed the content to github.
I used this as an opportunity to create a video of using Magit in Spacemacs. The video covered how to create a new local Git repository, create the first commit, add a remote repository and push the commit to the remote. This should be exactly the same for GitLab.
https://www.youtube.com/watch?v=AdEOazt1rD0
I embedded the video in the section on creating a local Git repository
I also took the opportunity to add the very cool Git Timemachine, which provides an easy way to navigate the code commits for a particular file and see the file contents change as you visit each commit. The Git Timemachine is very useful for reviewing how a file has evolved. Its also useful for live coding
demos where you dont want to show how a project has evolved, but dont want to waste time doing all the typing.
https://practicalli.github.io/spacemacs/magit/timemachine.html
Community events are fun and quite a responsibility too. Today we reviewed the speaker schedule for ClojureX, aiming to make the best flow of the talks and ensure we give the best possible experience for the audience and the speakers. Also organising a workshop before the ClojureX conference at uSwitch. We also have a hack day on 15th December along with the Scala community.
The evening was the Clojure dojo at uSwtich were we…
Added the ClojureBridge London workshop as a link on my Practicalli website. The workshop is complete, unlike most of my other books, so good to show (myself at least) that I can finish one. Will focus more on finishing the Spacemacs book and reworking the Clojure Practicalli book.
Updated all the links to my books to use https rather than http, as this makes Google and other search engines happier.
I paired with a friend who is starting to learn Clojure and we used GraalVM to create a native binary from a Clojure application.
While I set them up with Clojure via brew install clojure
and installing Leiningen, I installed GraalVM
GraalVM is just a tarball (Linux, Macosx) that is extracted and the bin directory added to the executable path. It turns out later that I also needed to install zlib
to create the native image from my Uberjar file. I assume the Uberjar file used zlib compression, or perhaps the zlib library is used to compress the native binary in some way. Either way, it was just a matter of sudo apt install zlib-dev
.
Development of the Clojure app wasnt any different from normal. We did use the Leiningen app
template to add code and configuration to allow our Clojure application run from the command line, via java -jar target/uberjar/my-app-standalone.jar
Once the code was written the application was packages using lein uberjar
.
By installing GraalVM and putting it up front in the executable path, the GraalVM version of Java is run when running java -version
. To check Clojure the application still works on GraalVM we just needed to run it via the command line.
GraalVM has a command to create a native binary
Discussing approaches for setting environment variables for Clojure applications. Its quite common to use environment variables for key settings, like the port of your web application using, although using a map for your configuration is more prevalent when there are lots of environment variables to set.
Using keyboard symbols for certain keys can make documentation easier to follow, e.g. for arrow keys. I could use some CSS with the <kbd>
tag, although adding html tags makes markdown less clean. Using unicode characters works really well though and of course Spacemacs makes it easy for you to add these characters by name using SPC i u
.
Using org-mode continues to be much more fun that markdown for writing this journal. I updated the orgmode section with useful stuff I found. I also just discovered adding (and editing existing) links using , i l
. I also looked at the insert orgmode keybinding, but it generates quite a lot of text and I suspect its something that needs to be exported to work with github
@@html:<kbd>@@ <right> @@html:</kbd>@@
Separate environment variable definitions are used when you have a small number of settings, e.g. for PORT, often using the https://github.com/weavejester/environ library.
Using maps is also a good approach, especially where there are a great number of settings for different environments. The https://github.com/juxt/aero library is a nice clean way to specify a collection of environment settings across multiple environments.
In my last project, we deployed in dev, qa, uat and prod environments with multiple services (oracle, tibco, datomic, etc) and used aero to great effect.
Sayid debugger package and clj-refactor are no longer loaded by default.
Sayid has caused a few issues with Cider recently so it is left to the user to decide if it is useful for them.
clj-refactor has not been updated in several years and some of its functionality is moving into clojure-mode.
Both these packages can be included by defining their package names as :variables on the clojure layer
Overview of projectile for working with files only from the current project, making it easier to open files and navigate buffers for a project.
Using helm transient state to help tidy up buffers.
Used SPC i u
to add unicode characters for arrow keys, e.g.🡄🡇🡅🡆
Added a new section on Linting tools, providing a quick overview of linting tools I use for my Clojure projects, Joker and Eastwood.
Joker is simpler to use, thanks to the clojure-lint layer. It does use an external binary, which I placed on my existing executable path. Joker uses a sub-set of Clojure so it may give a few inaccuracies, these are usually false positives on things like macros. There is a way to tell joker to ignore certain symbols though.
Still a bit of work to do on these sections, but they cover the basics.
Had a quick look at the many Clojure extensions for VisualStudio Code. [Calva](https://marketplace.visualstudio.com/items?itemName=cospaia.clojure4vscode) seems the most maintained. It requires you to start a repl outside of the editior, which I am not that keen on as it means more complexity. However, it seems to generally be the better choice.
A developer considering Clojure reached out to me with the following question.
— I have these two types of class definitions in Java:
public class SomeClass { public void generateFor(SomeArgType argument); } ----- or ----
public class SomeClass { public SomeType generateFor(SomeArgType argument); }
How do you write them in Clojure if you even write any such definitions to start with. I know you dont have types or interfaces or classes as such. —
It was an interesting reminder of where I had come from several years ago. OO languages and especially Java have become the main-stay of much application development because its a very stable language (Java) with a highly optomised runtime environment (JVM). My journey into Clojure has allowed me to use a much simpler syntax with barely any boilerplate code. I find it quite challenging to go back to the Java and OO way of thinking.
So, I tried to answer the question with as meaningful an answer as possible, so I just wrote some code and explained how it worked.
— Here is a simple function which would typically be defined in a namespace (a package in Java).
This function just generates a message, so nothing very exciting in this code. First we define a function, as you would define a method, but we dont need to do it in a class. The function takes one argument and returns what ever is the result of the last expression (no need to define an explicit result call.
The If function determines which is the last expression to be called. If the condition, (= feature “function”) - compare the value of feature with the string “function”, is true then use the first line after the condition, if false then use the second line. If is a macro, so acts slightly different to normal function evaluation.
(defn feature-generator
"I am a very simple function, this is my docstring
Usually I would tell you something useful about myself"
[feature]
(if (= feature "function")
(str "In Clojure everything is a" " " feature)
(str "Clojure doesnt use:" " " feature)))
Now we have the function defined, with a name that we can call it by, we can call it anywhere in our namespace (or in another namespace if we add it to that namespace).
Here is the function call, followed by the result as a comment underneath
(feature-generator "objects")
;; => "Clojure doesnt use: objects"
Lets call it again with a different argument
(feature-generator "classes")
;; => "Clojure doesnt use: classes"
And we can use the function call inside another function call… this is how we build up our application.
Here we call the str function that joins two things together to make a string. The first argument to str is the result of a function call, so the Clojure runtime (the REPL) first goes and evaluates that function which is then passed to the str function along with the string as a second argument
(str
(feature-generator "function")
", with persistent data structures, eg maps, vectors")
;; => "In Clojure everything is a function, with persistent data structures, eg maps, vectors"
This is a very quick example of defining your own behaviour in Clojure and calling it.
The other important aspect of Clojure is to model data, for which we use either lists (linked list), vectors (an array), maps (hash map), sets (unique values). We dont need generics here and we dont need to define types of our data (although we can define a specification, usually if we are pulling data from outside of Clojure).
If we were going to model different science fiction worlds, we could construct a data structure as follows
(def starwars
{:characters
{:jedi ["Luke Skywalker"
"Obiwan Kenobi"]
:sith ["Darth Vader"
"Darth Sideous"]
:droids ["C3P0"
"R2D2"]}
:ships
{:rebel-alliance ["Millenium Falcon"
"X-wing figher"]
:imperial-empire ["Intergalactic Cruser"
"Destroyer"
"Im just making these up now"]}})
We have bound the name starwars to a maps of maps with vectors.
There are lots of functions that help us get or update (creates a new data structure) this data structure
Lets start simple and get a value from the map using a key
(get starwars :characters) ;; => {:jedi ["Luke Skywalker" "Obiwan Kenobi"], :sith ["Darth Vader" "Darth Sideous"], :droids ["C3P0" "R2D2"]}
We can see that the result itself is a map, so we could use another get function around the first to drill down further in the map. Clojure has a function that allows you to traverse the path in the map though.
(get-in starwars [:characters :jedi])
;; => ["Luke Skywalker" "Obiwan Kenobi"]
The developer was appreciative of the detailed answer, however, as this was all over email its hard to know how well they understood the examples. I will suggest some resources they can use to learn.
Spacemacs org-mode is a much richer experience when it comes to writing when compared to markdown in Emacs. Thanks to Bobby Towers for reminding me that I should be using org-mode to write this journal. Being able to fold up headings in org-mode, add code blocks that evaluate and move sections around easily are well worth the conversion of this file from markdown.
This was a simple case of opening Magit SPC g s
and renaming the file using the !
keybinding to bring up a prompt that runs any git command you type. There is no specific rename file option in Magit (that I am aware of), so this is a convenient way to run those odd git commands.
Converting from markdown to org-mode is fairly simple, especially with all the Vim editing tricks I have learnt over the last few weeks.
Source code blocks use the #+BEGIN_SRC
directive, rather than three back-tics in markdown. The advantage with org-mode is that your code is syntax highlighted in the editor and actually executable (via org-mode Bable). So it is much easier to establish you have working code in your documentation.
For inline code and shell command references, we can just surround with ~ to highlight as a mono-type font face.
Hyperlinks are the same way around as they are defined in HTML, the link first and then the anchor text. Not sure why markdown is the reverse. The link and anchor text are each surrounded with square brackets, e.g. [http://spacemacs.org] and [Spacemacs], then both are wrapped inside another pair of square brackets to make the link. Org-mode then renders the text so the anchor is now a hyperlink in your text, only showing the anchor text.
How well this all works we will discover when I push this big change to Github.
Spacemacs is infinitely hackable, but learning to use the features it just gives you is much quicker :)
I love writing my Spacemacs book and its great to see others finding it useful.
I keep finding more ways to do things faster, mostly by accident as I pressed the wrong key. I have found a few menus on the keys # * g z
that I wanted to investigate and today was the day.
I use g
for commenting code g c c
and for toggling character case v g ~
or word case SPC v g ~
Interesting discussion on how Spacemacs does code folding in the #spacemacs channel of the London Clojurians Slack community. A suggestion was made about folding different levels of code, in a similar manor to org-mode and magit (magit has the stage, file and hunks that can be expanded and collapsed).
I was not particularly convinced that changes were needed at first. After experimenting I did think that the collapsing of function definitions could be made better for me. Currently the argument list is collapsed on a function and it would be really useful to keep that shown, along with the def function-name
. If there was a docstring (and there really should be) then that sting would be collapsed too, or just show the first line.
The default code folding uses some Vim magic and I didnt see an easy way to configure the behaviour. It is easy to change code folding to a package called [origami](https://github.com/gregsexton/origami.el#does-it-support-my-favourite-major-mode) which enables you to write your own parser in order to create custom folding for your language.
There is also [evil-vimish-fold](https://github.com/mrkkrp/vimish-fold/blob/master/vimish-fold.el) which some have commented to be really good for every language, however, I dont think this has been added to Spacemacs as a layer yet. I am trying out Origami now, but it seem less useful for Clojure than evil-fold, as folding seems to only work at the top level. I could be doing something wrong, or the Clojure parser for origami needs tweeking. I would love to see the argument list still shown when folding, as an example.
To try the evil-vimish-fold package without a layer, you can add it to your .spacemacs
file as follows
- add the package name
evil-vimish-fold
todotspacemacs-additional-packages
- add
(evil-vimish-fold-mode 1)
touser-config
Starting to change the HackTheTower website into HackTogetherLDN.
Supporting new speakers at the New Speaker night organised by the London Java Community.
Oh my, its October already!
Hacking on my [Practicalli Spacemacs](https://practicalli.github.io/spacemacs) book. Emacs is a continual joy when it comes to optimsing the process of capturing all the wonderful thoughts my brain has.
Adding more content and exercises based on the feedback from the ClojureBridge London event.
A server side web app that tells you the distance between two cities
Taking some of the feedback we received from the workshop, I updated some of the examples and exercises in the [ClojureBridge London workshop](https://clojurebridgelondon.github.io/workshop/) and started a guide for the larger example of building a website to show the distance between two cities.
With the project created, we started the server with lein ring server
to check it all worked. To start building the page we added the [hiccup]() library, allowing us write an html web page using just Clojure code. The hiccup.page/html
function creates a web page and we define a [:head ]
section that contains include-css
and include-js
functions so we can add bootstrap to our website and use some simple styles to make the site look better.
The data for the countries was defined within a Clojure map, e.g. {:city "London" :latitude 51.5074 :longtitude 0.1278}
. We added a dozen cities as maps to a Clojure vector and bound that vector to the symbol locations
.
To select the cities from the web interface, we added a form-to
function that included two input drop-downs. Using a for
statement we iterated over the locations
collection and extracted the city name, placing it into the drop down. This gave us a to and from location to select.
Using the submit button to call a results page, we extracted the selected cities from the request params. Then called a function that calculated the distance between two locations using their respective latitude and longtitude positions.
I get a wonderful warm feeling when helping people get into the software industry, especially when its addressing the balance of voices in that industry. To be able to help those new to development using my favourite language, Clojure, makes it extra special.
Clojure is quite different from most languages, specifically in the way it encourages you to think about the design of your code. The simplicity that is achievable with Clojure is something that continues make me smile every day, even after 8 years of learning and working with Clojure.
The ClojureBridge event had over 20 women enjoying the day. Six women already had some experience coding and one of them had just found out they had got their first job in the industry. The rest of the students were very new. Everyone was very excited about the day and that enthusiasm carried on throughout the day.
I was coaching 4 women who had some coding experience. Two of them had completed the first 6 levels of the workshop exercise in the afternoon and started building websites using Clojure.
Each student took a slightly different approch. One student followed my [Practicalli Clojure WebApps]() step by step guide to building a server side web application with ring and compojure. The second student used the [leiningen compojure template]() to start building a server side website that calculated the distance between two cities.
With the project created, we started the server with lein ring server
to check it all worked. To start building the page we added the [hiccup]() library, allowing us write an html web page using just Clojure code. The hiccup.page/html
function creates a web page and we define a [:head ]
section that contains include-css
and include-js
functions so we can add bootstrap to our website and use some simple styles to make the site look better.
The data for the countries was defined within a Clojure map, e.g. {:city "London" :latitude 51.5074 :longtitude 0.1278}
. We added a dozen cities as maps to a Clojure vector and bound that vector to the symbol locations
.
To select the cities from the web interface, we added a form-to
function that included two input drop-downs. Using a for
statement we iterated over the locations
collection and extracted the city name, placing it into the drop down. This gave us a to and from location to select.
Using the submit button to call a results page, we extracted the selected cities from the request params. Then called a function that calculated the distance between two locations using their respective latitude and longtitude positions.
Running our 8th ClojureBridge London event to support under represented groups gain experience and build confidence when it comes to codeing.
Updated some of the ClojureBridge content and examples.
Some ClojureX conference management.
Some more user research. Buiding websitest that tell you something isnt as easy as it seams.
Making good used of Layouts in Spacemacs to organise my work more effectively.
Continued with building up the SVG library
More hacking on the SVG library I have been working on in the status-monitor app. Continuing to define example SVG elements in Clojure.
More experimenting with SVG and included some simple HTML. At some stage will need to decide what styles to include inline for HTML elements, what to include as templates and what to define as CSS (and any other / additonal css libraries to use).
https://github.com/jr0cket/webapp-status-monitor/commit/93189468fc80938865fb67f4ff6de77f9d4bc724
Hacking with more SVG graphics and wrapping those graphics with HTML.
Debugging the html output is very easy with the Chrome Inspector.
Today was distracted with issues raised around this years ClojureX conference. Although we strive to get as much balance as possible in the speakers for our annual conference and the last few years have been quite successful, unfortunately we only have a few women speakers confirmed this year. We spend time reaching out to under represented groups and supporting them in many ways to get involved with the conference. We do reach out to speakers we want to appear at the conference and this also has a bias to ensure we have a good balance. Although we have been very successful encouraging new speakers to the conference, the representation of those new speakers has not been as broad this year. One of our speakers pulled out of the conference as they understandably felt it was not appropriate to speak, especially as they were pair presenting with a colleague who would have contributed to the balance we strive to achieve. Luckily the speaker had two other colleagues who would bring the same balance that we were hoping for.
Unfortunately this took up most of the day today and didnt leave much time for coding before heading off to run the Coding dojo at Thoughtworks. Unfortunately Yolina who has done a wonderful job of running these events for the last few years was ill. I hope Yolina a swift recovery.
The Clojure code dojo was lots of fun tonight. We had 3 groups of people fairly new to Clojure, working through lots of 4clojure.com exercises. We also had a group creating a notification app for the Park Run events. Unfortunately this popular site does not have a published API, so lots of webscraping with the enlive library was in order. I spent most of the time coaching the teams through the 4Clojure exercises, helping them to think in a functional way. We also had a very interesting discussion around functional design patterns and what if any were the relationships between functional and OO patterns. Our conclusion being that most of the OO patterns provide features that are not available in the language. Understanding functional design or patterns is more about understanding the Clojure (or Lisp) style of functional programming and what is the so called idiomatic
approach to Clojure.
I still managed to get some time to work on the Status Monitor, although this was more about defining SVG elements and considering creating a library of SVG components to make it easier to incorporate them in Clojure or ClojureScript projects.
The day ended on a high note with my pull request to the Compojure Leiningen template merged by @weavejester
Not much coding today, so no real detail to cover.
Created a new namespace in the status-monitor application for svg-components. Planning to start converting the Mozilla SVG guide and SVG Elements Reference.
Refined the tests using the ring.mock.request
mocking library that Compojure Leiningen template added when creating the project.
https://github.com/jr0cket/webapp-status-monitor/commit/a71781610e800f524ce46dfdb0e18653aea19c2d
The test from yesterday was not quite as elegant as it could be. Although it showed clearly what it was testing, there was much duplication.
#_(deftest test-monitor-dashboard
(testing "Test dashboard contains key pieces of information"
(is (clojure.string/includes?
(monitor-dashboard {})
"<title>Area51 Mock Status</title>"))
(is (clojure.string/includes?
(monitor-dashboard {})
"<link href=\"//stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css\" rel=\"stylesheet\" type=\"text/css\">"))
(is (clojure.string/includes?
(monitor-dashboard {}) "<div class=\"jumbotron\"><h1>Mock Status Monitor Dashboard</h1></div>"))
(is (clojure.string/includes?
(monitor-dashboard {}) "<h2>Application monitor</h2>"))
(is (clojure.string/includes?
(monitor-dashboard {})
"view-box=\"0 0 100 20\""))))
I refactored the above test to use a let function to create a local binding called response, bound to the value of calling the webapp route /dashboard
. This testing the correct flow of our webapp route and its response.
The let name response
was bound to the /dashboard
response by calling (app (mock/request :get "/dashboard"))
from the ring.mock.request
mocking library.
The response is a Clojure map which has a key called :body
that contains the html output for the web page. So I extract the value using the :boot
key.
Added clojure.string
to the namespace with an alias string
so I could simply call string/includes?
instead of clojure.string/includes?
. I could refer includes?
into the namespace, however, I prefer to be explicit in the use of libraries (unless there is extensive use of specific functions in a namespace that is focused on the context of those functions, i.e. a UI namespace that uses Hiccup).
So, the refactored test now looks a little more streamlined.
(deftest test-monitor-dashboard
(testing "Test dashboard contains key pieces of information"
(let [response (app (mock/request :get "/dashboard"))]
(is (= (:status response) 200))
(is (string/includes?
(:body response)
"<title>Area51 Mock Status</title>"))
(is (string/includes?
(:body response)
"<link href=\"//stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css\" rel=\"stylesheet\" type=\"text/css\">"))
(is (string/includes?
(:body response) "<div class=\"jumbotron\"><h1>Mock Status Monitor Dashboard</h1></div>"))
(is (string/includes?
(:body response) "<h2>Application monitor</h2>"))
(is (string/includes?
(:body response)
"view-box=\"0 0 100 20\"")))))
More testing today and taking a brief look at the mocking framework that Compojure Leiningen template added to the test code generated.
Also has a quick look at eftest from @weavejester which is supposed to be faster and can run more tests in parrallel than just running lein test
. I mainly wanted to use it for the coloured output at this stage (as I only have a few tests).
By accident I found the Emacs transpose keybinding is still in Spacemacs today. Instead of pressing M-TAB
I was pressing M-t
and swapping around the two words either side of the cursor position. The transpose call even jumps over and ignores comments and other separators.
The standard Spacemacs bindings for transpose are as follows:
This is something else to add to my Spacemacs for Clojure development guide.
https://github.com/jr0cket/webapp-status-monitor/commit/b5f8b2a83ce9839c7881b4a5b80d8d7911b13fb2
https://github.com/jr0cket/webapp-status-monitor/commit/d2016c004b9122677986f3933270e900ce59d0a8
https://github.com/jr0cket/webapp-status-monitor/commit/f5eed17e129ffd2e6c402d1292fb900164129259
https://github.com/jr0cket/webapp-status-monitor/commit/bfa92e18ebb5b57c223c6b6851277ee88c1819c7
https://github.com/jr0cket/webapp-status-monitor/commit/f8b6bef2486fc972e0f82599b9303c0616ef5195
Perhaps a little superfluous but an easy thing to add is an ascii text logo of the project name. I use the text to ascii art generator (TAAG) and the Fire Font.
The output of the generator was copied into a text block in the project README.md
file.
Confirming the output of the monitor-dashboard
function by calling that function via the REPL, using an empty map {} as the function argument.
The monitor-dashboard
is currently passive and so does not use any data from the request map.
If the monitor-dashboard
function did use data from the request map, we would need to mock that in the call to monitor-dashboard
.
Using clojure.string/includes?
to see if the result of calling the monitor-dashboard
function includes specific sub-strings.
This could be done using the mock framework and put into a let to make the code cleaner.
(deftest test-monitor-dashboard
(testing "Test dashboard contains key pieces of information"
(is (clojure.string/includes?
(monitor-dashboard {})
"<title>Area51 Mock Status</title>"))
(is (clojure.string/includes?
(monitor-dashboard {})
"<link href=\"//stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css\" rel=\"stylesheet\" type=\"text/css\">"))
(is (clojure.string/includes?
(monitor-dashboard {}) "<div class=\"jumbotron\"><h1>Mock Status Monitor Dashboard</h1></div>"))
(is (clojure.string/includes?
(monitor-dashboard {}) "<h2>Application monitor</h2>"))
(is (clojure.string/includes?
(monitor-dashboard {})
"view-box=\"0 0 100 20\""))))
Tomorrow I’ll refactor the above test to use a let
value for the response from calling monitor-dashboard. I will also use the (app (mock/request :get "/"))
call in the let
and compare the :body
from the response.
eftest provides a faster testing tool and syntax coloured reporting of results, making it nicer to use that lein test
.
Run the tests using the eftest plugin on the command line using lein eftest
The plugin uses several dependencies
[/images/clojure-testing-eftest-dependencies.png][Clojure Leiningen eftest plugin dependencies]
The output in this test run that contains two test failures is very clear to understand and spot the issues easily.
[/images/clojure-testing-eftest-test-run-failures.png][Clojure Leiningen eftest plugin - failing test run]
Started coaching a developer today. It has been a few months since I coached, so am happy to be starting again. Coaching really does help me exercise my mind and it is very enjoyable to guide someone.
One decision taken in the coaching was which continuous integration server to use. I realised I should start writing some tests and set up a CI server for the status monitor project. The simplest approach for a CI server was to use [CircleCI](https://circleci.com/) that provides CI as a service and hooks up easily to Github projects. CircleCI is also written in Clojure, so its great to support them.
https://github.com/jr0cket/webapp-status-monitor/commit/2647704466ea05c3fb6ba3eba46fa28d341000e7
https://github.com/jr0cket/webapp-status-monitor/commit/f7912e1e8151b3c399bd3c4e517d3a7d11709f8e
There is a really good getting started guide on the CircleCI website.
Adding a project and CircleCI detects the programming language and your operating system.
Added the sample config.yml
to the project as .configci/config.yml
. The only change made to the config file was to update the version of Leiningen to 2.8.1 (was version 2.7.1). Once this was added to the project and pushed up to the github repostitory, then we are ready to create a build.
This launches the project on CircleCI and webhooks listen for new commits to the Github repository.
Adding a status badge to the Github readme was very simple too. CircleCI provides the Markdown to add to the README.md page.
The Compojure template comes with a few tests that nicely show how to group tests and give some hints on things to test.
Started adding tests to check the output generated by the visual components I am developing to represent the elements of the dashboard.
I created a Slack community specifically for the coaching, so we can keep our discussions around for several months if required. We discussed what was to be achieved (at least initially) from the coaching, tooling and development experiences.
This morning I had a great conversation with an exciting company that is looking to move to Clojure for key computational parts of their systems. Lots of discussion centred around finding and hiring Clojure developers, for which there are many options.
The rest of the day was spent working on my book [Spacemacs for Clojure development](https://github.com/practicalli/spacemacs-gitbook/).
https://github.com/practicalli/spacemacs-gitbook/
I have been steadily creating content for my book to help developers make the most out of Spacemacs for Clojure development. There is still much content to go, however, there is lots of really useful things I have learnt and added over the last few weeks.
I have also been adding more content ideas in the Github project for the book.
Preparing for the ClojureBridge London event next weekend by reviewing the workshop content and enhancing some of the challenges and sample answers.
Also carried out some user research for developer portals of several financial institues. There was definately a large difference in usability and developer experience between the sites reviewed. Hopefully my comments are of some contructive use and I wasnt overly critical.
https://github.com/ClojureBridgeLondon/workshop-content-gitbook
Improved several sections of the ClojureBridge workshop content.
I was at an Amazon for an Alexa workshop building what they refer to as skills, their word for defining the things that you can configure Alexa to do. It was good fun, very well explained and I also won an Echo dot (which should arrive in the post tomorrow).
This evening I coached at Codebar, helping a very bright person with their Augmented Reality application for Android which was written in Kotlin. I can see why experienced Android developers are able to get a great rate for their work, as it feels like a lot of moving parts to build such a native app. They managed to get further with the app and we even got some UI tests instrumented.
Not progress on the Clojure app today, although had a very interesting talk about the need to do more to highlight what makes Clojure so special. I did do some work on this for ClojureBridge London workshop https://clojurebridgelondon.github.io/workshop/introducing-clojure/
To make voice work, the service needs to understand millions of words so that it can accurately interpret what you are saying and have a better chance of doing the right thing. If Alexa doesunt understand the words you say, then its not going to do what you want.
The Alexa Framework can be used to enable any device, not just the devices from Amazon.
They are called skills (rather than voice apps) as we are teaching Alexa to do something specific.
Today was a great meetup at Signal Media. Talked about the #100daysofcode challenge I am doing and the experiments with Scalable Vector Graphics. Discussed the case for ClojureScript and Reagent over JavaScript and React.js
Also helped someone on Clojurians Slack write a keybinding for [lispy]() functions lispy-pair
and lispy-quote
that did not have keybindings defined in the package. Lispy is an alternative to Evil and Smartparents and whilst interesting, its not something I am inclined to try myself.
There are so many companies using Clojure I keep finding out about. The TV company Vue.tv uses Clojure for all their data processing around their broadcasting business.
GraphQL in a lambda works surprisingly well according to Alex’s talk. That was really interesting.
https://github.com/jr0cket/webapp-status-monitor/commit/1c282057c2d1a7433a36ad50b2845c79e788f128
I’d like to test out the SVG dashboard with a number of different data sets. Rather than just type a lot of random numbers into the code, I wrote a mock-data generator function. This mock data first returned float values.
(defn mock-data
"Mock data generator"
[maximum-value]
(rand (+ maximum-value 1)))
The mock-data
function was refactored to generate either float or integer random data based on the type passed to the mock-data
function as an argument.
As the float generated number has multiple decimal places and we only want two for the display, the format
function is used to limit the precision of the returning number to 2 decimal places.
(defn mock-data
"Mock data generator"
[maximum-value]
(if (float? maximum-value)
(format "%.2f" (rand (+ maximum-value 1)))
(rand-int (+ maximum-value 1))))
As I was experimenting with a mock-data generator in the REPL experiments section, I noticed that Joker reports out of order issues. So it will highlight if you try to call a function before its defined in the file. This happens even if the function has already been evaluated in the repl. This situation does remind me that Joker reads the whole Clojure file each time a change is made.
I am finding Joker invaluable to guard against very silly mistakes and thus avoiding hunting through code for silly mistakes.
More Joker awesomenessness.
I had a little excursion into Joker, a linter for Clojure. Someone was having problems getting the clojure-lint layer to work in Spacemacs, so I though I would give it a try and see if I could help. I really like the feedback I get from the Joker linter, its very clearly presented and is very fast.
I like coding interfaces with Scalable Vector Graphics (SVG) as the graphics are defined as data structures (when using the hiccup syntax). So SVG is really easy to use with Clojure. It requires a little trial and error as its not specifically documented as far as I can tell, but having a repl means is really quick to experiment.
https://github.com/jr0cket/webapp-status-monitor/commit/4d7925184c8cf181f0addfb8fb829844ba56002d https://github.com/jr0cket/webapp-status-monitor/commit/17efddc7233fb134b107c89f88fe3875ff40f83c
I added some mock status bars to my status-monitor application, using hiccup and [Scalable Vector Graphics (SVG)](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics) to add some colour and design to the page.
There is a bit of a challenge with using SVG with the Hiccup syntax, as it does not seem to be documented anywhere. However, its not that hard to work out by looking at the [SVG elements in HTML](https://developer.mozilla.org/en-US/docs/Web/SVG/Element). We are generating HTML after all.
I did find some SVG projects that may be interesting to try: > Tikkba for the creation and the dynamic modification of SVG documents > analemma for generating charts and Scalable Vector Graphics (SVG) > dali for representing the SVG graphics format. It allows the creation and manipulation of SVG files. The syntax used to describe the graphical elements is based on hiccup with a few extensions > svg-wrangler a collection of Clojure functions to help assemble SVG images via hiccup data structures
I setup on Joker on ubuntu by downloading a pre-compiled linux binary and placing it in ~~/bin~ which is already on my executable path.
Added the clojure-lint
layer to .spacemacs
configuration file and restarted Spacemacs with SPC q r
.
Opened my status-monitor status-monitor.handler
namespace and it showed me where I had been less clear with my code straight away.
If I call a function with the wrong number of argument then Joker will put an orange dot in the margin. That’s so awesome.
I will refactor a few things that Joker found tomorrow, such especially refining the namespace refer.
Today was more a journey of discovery on how projects from the compojure-template can be run and how the lein-ring plugin works.
I really appreciated the work done by all Open Source project owners and maintainers, especially @weavejester who has created so many great projects for Clojure.
I didnt write a lot of code today, but felt I learnt some really invaluable information. It also feels good to give back to an open source project, no matter how big or small the contribution.
Not having to concern myself with a delivery date for my project allowed me the feedom to dive into the projects and tools I have been using for quite a while. This has given me a much better understanding of how to get the most out of them and help me teach other developers how to use them. It is also way more fun.
I submitted a [pull request](weavejester/compojure-template#25) to update the each library dependency to their latest stable version in the compojure-template.
Here is what I got up to in a lot more detail.
When creating a new project from the [compojure-template]() yesterday I noticed that the version of libraries used in the template were a little dated. Those versions stil work, but I decided to create a pull request with the latest stable versions of those libraries.
weavejester/compojure-template#25
There was an existing pull request to update the libraries dependencies, however, that was also out of date.
The compojure-template
project only describes how to run a generated project using the lein-ring plugin, using lein ring server
. The lein-ring project readme describes how to run the project from the Java command line, but there is no reference to this information on the compojure-template project. Again, I spotted a pull request to add these details to the readme so I added a thumbs up reaction with hope the maintainer will accept the pull request.
It is common in Clojure projects to define a -main
function that is the start point to running the application. However, the compojure-template doesnt generate a project with a -main
function, instead it defines a Var called app
that is the start of our application.
The reason for this approach is so that the compojure application can be packaged into a Java Web Archive (WAR) file and dropped into an existing Java Application Server (Tomcat, Jett, etc.). This is the traditional approach to deploying a JVM webapp.
The lein-ring plugin adds a task called ring
to Leiningen, so you can start the application on the command line using
lein ring server
Running the compojure project using lein-ring plugin starts an embedded Jetty web application server and passes the app
to that running process to start listening for http requests.
With the rise in Cloud computing it is more common to run each application in its own embedded server, rather than deploying mulitple apps on a single applicaton server. This new approach enables vertical scaling and parallel processing, something Clojure is an excellent language for.
Rather than write our own -main
function to call Jetty, we can ask lein-ring plugin to do it for us. A -main
function is boilerplate code after all.
Use the lein-ring version of lein uberjar
to generate a JAR file
lein ring uberjar
Taking a look at the contents of the generated JAR file we can see the additions made by the plugin.
> I use Spacemacs to open the Jar file as it will list all the files and let me read each text file it contains.
An application entry point has been added to the meta-inf/manifest.mf
by specifying Main-Class: status_monitor.handler.main
Hold on though… we didnt have a main
namespace in our code, so how does that work?
Well, lein-ring had created a file for that namespace with a -main
function within it. Here is the code contained within this automatically generated namespace.
(do
(clojure.core/ns status-monitor.handler.main
(:gen-class))
(clojure.core/defn -main []
((do
(clojure.core/require (quote ring.server.leiningen))
(clojure.core/resolve (quote ring.server.leiningen/serve)))
(quote {:ring
{:handler status-monitor.handler/app,
:open-browser? false,
:stacktraces? false,
:auto-reload? false,
:auto-refresh? false}}))))
The code requires the namespace ring.server.leiningen
so ic can run the serve
function that takes the app
as an argument. serve
will run an embedded jetty server and run our app
within.
As uberjar
is typically used to deply your application to a remote server (e.g. uat, production), then development features are set to false. We dont really want a browser window to be opened when we run the app on a production server.
Started a simple status monitor application to collate monitoring information from different sources into one simple web dashboard.
The compojure template is easy to get started with, it just works with the help of the lein-ring
plugin. The plugin takes the app defined in the src/status_monitor/handler.clj
file and passes it to an embedded Jetty application server. The plugin abstracts this detail away, making the project easy to run and less code to write.
This abstraction does make it a little harder to understand how this application actually runs and there is a lack of information on the template website.
https://github.com/jr0cket/webapp-status-monitor
Started a new project using the Leiningen [compojure-template](https://github.com/weavejester/compojure-template)
lein new compojure status-monitor
This created a project using the ring
and compojure
libraries and Clojure 1.8.0
:dependencies [[org.clojure/clojure "1.8.0"]
[compojure "1.5.1"]
[ring/ring-defaults "0.2.1"]]
The project was updated to use the creative commons licence, rather than the deffault Eclipse public license which has is more restrictive.
Version 1.9.0 is now the current stable version of Clojure, so that has been updated in the dependencies.
The lein-compojure template is very simple to get started with, although it seems the libraries are a little behind the latest. The project runs successfully without upgrading versions. It is usually better to use the latest stable versions of these libraries to pick up any fixes.
The latest stable versions were found via https://clojars.org/.
> Consider submitting a pull request to update the lein-compojure template project on Github.
Although the project runs well from the command line using the lein-ring
plugin, we dont get the full benefit of the REPL until we connect our editor to the REPL. With the Compojure template you need to run the repl from Spacemacs as there is no way to connect to the REPL port from Spacemacs when the project is run with lein ring server
.
Using the keybinding , '
is a quick way to start the repl in Spacemacs.
The website is a litle basic in terms of output, so I added Bootstrap CSS and JavaScript libraries to the project as a simple way to make the output look a little more professional.
To use Bootstrap easily and avoid writing lots of html code, I used the Hiccup library. Hiccup allows you to generate html code from Clojure vectors that contain Clojure keywords representing html tags. Generating an html h1
header and its text is written as [:h1 "I am an HTML header"]
.
Using Clojure syntax in this way, makes it much easier to type. Using this syntax also makes it easy to use structured editing with your code.
The project needs to include Hiccup library as a dependency. Using the clj-refactor
tools in Emacs, I added the hiccup dependencies and also hotloaded it into the already running repl.
Created the basics of our monitor dashboard page without writing html direct.
Added the Hiccup library to generate html from Clojure data structures and keywords.
Using the hiccup.page/html5 function we created a page that allows us to include the Bootstrap CSS and JavaScript libraries. Hiccup allows us to include CSS styles in the data structures, or more usefully refer to the Bootstrap styles by name.
Test out my development environment is working. For the exercises I will be using Spacemacs, a community configuration for Emacs that also provides a comprehensive set of Vim states (Evil mode) that make editing code more effective.
Spacemacs is configured to use the Clojure layer, which pulls in CIDER packages, providing a comprehensive Clojure development environment that is equivalent to the features of an IDE without the resource requirements.
I will use Spacemacs for all coding and documentation for this 100 days challenge. Along the way I will document my usage of Spacemacs and useful practices in the online guide: [Practicalli Spacemacs](https://practicalli.github.io/spacemacs).
As today is just a check of my environment, then no progress to report yet.
I am a little nervous about this challenge as it will demonstrate just how much coding skill I currently have. My imposter syndome is kicking in a little as I think about it. However, the excitement of emersing myself in Clojure coding for 100 days is over-riding this nervousness and hopefully this will continue to the end of the challenge.
Practicalli Spacemacs My Github repository for 100 Days Of Clojure Code