First-class types
Dynamic typing means that you have first-class types: you can inspect, create and store types at runtime, including the language's own types.
It also means that values are typed, not variables.
Statically typed language may produce code that relies on dynamic types too, like method dispatch, type classes, etc. but in a way that is generally invisible to the runtime. At best, they give you some way to perform introspection. Alternatively, you could simulate types as values but then you have an ad-hoc dynamic type system.
However, dynamic type systems rarely have only first-class types. You can have first-class symbols, first-class packages, first-class .... everything. This is in contrast to the strict separation between the compiler's language and the runtime language in statically typed languages. What the compiler or interpreter can do the runtime can do, too.
Now, let's agree that type inference is a good thing and that I like to have my code checked before running it. However, I also like being able to produce and compile code at runtime. And I love to precompute things at compile-time too. In a dynamically typed language, this is done with the same language. In OCaml, you have the module/functor type system, which is different from the main type system, which is different from the preprocessor language. In C++, you have the template language which has nothing to do with the main language, which is generally ignorant of types during execution. And that's fine in those language, because they don't want to provide more.
Ultimately, that does not change really what kind of software you can develop, but the expressivity changes how you develop them and whether it is hard or not.
Patterns
Patterns that rely on dynamic types are patterns which involve dynamic environments: open classes, dispatching, in-memory databases of objects, serialization, etc. Simple things like generic containers work because a vector does not forget at runtime about the type of objects it holds (no need for parametric types).
I tried to introduce the many ways code is evaluated in Common Lisp as well as examples of possible static analyses (this is SBCL). The sandbox example compiles a tiny subset of Lisp code fetched from a separate file. In order to be reasonably safe, I change the readtable, allow only a subset of standard symbols and wrap things with a timeout.
;;
;; Fetching systems, installing them, etc.
;; ASDF and QL provide provide resp. a Make-like facility
;; and system management inside the runtime: those are
;; not distinct programs.
;; Reflexivity allows to develop dedicated tools: for example,
;; being able to find the transitive reduction of dependencies
;; to parallelize builds.
;; https://gitlab.common-lisp.net/xcvb/asdf-dependency-grovel
;;
(ql:quickload 'trivial-timeout)
;;
;; Readtables are part of the runtime.
;; See also NAMED-READTABLES.
;;
(defparameter *safe-readtable* (copy-readtable *readtable*))
(set-macro-character #\# nil t *safe-readtable*)
(set-macro-character #\: (lambda (&rest args)
(declare (ignore args))
(error "Colon character disabled."))
nil
*safe-readtable*)
;; eval-when is necessary when compiling the whole file.
;; This makes the result of the form available in the compile-time
;; environment.
(eval-when (:compile-toplevel :load-toplevel :execute)
(defvar +WHITELISTED-LISP-SYMBOLS+
'(+ - * / lambda labels mod rem expt round
truncate floor ceiling values multiple-value-bind)))
;;
;; Read-time evaluation #.+WHITELISTED-LISP-SYMBOLS+
;; The same language is used to control the reader.
;;
(defpackage :sandbox
(:import-from
:common-lisp . #.+WHITELISTED-LISP-SYMBOLS+)
(:export . #.+WHITELISTED-LISP-SYMBOLS+))
(declaim (inline read-sandbox))
(defun read-sandbox (stream &key (timeout 3))
(declare (type (integer 0 10) timeout))
(trivial-timeout:with-timeout (timeout)
(let ((*read-eval* nil)
(*readtable* *safe-readtable*)
;;
;; Packages are first-class: no possible name collision.
;;
(package (make-package (gensym "SANDBOX") :use '(:sandbox))))
(unwind-protect
(let ((*package* package))
(loop
with stop = (gensym)
for read = (read stream nil stop)
until (eq read stop)
;;
;; Eval at runtime
;;
for value = (eval read)
;;
;; Type checking
;;
unless (functionp value)
do (error "Not a function")
;;
;; Compile at run-time
;;
collect (compile nil value)))
(delete-package package)))))
;;
;; Static type checking.
;; warning: Constant 50 conflicts with its asserted type (MOD 11)
;;
(defun read-sandbox-file (file)
(with-open-file (in file)
(read-sandbox in :timeout 50)))
;; get it right, this time
(defun read-sandbox-file (file)
(with-open-file (in file)
(read-sandbox in)))
#| /tmp/plugin.lisp
(lambda (x) (+ (* 3 x) 100))
(lambda (a b c) (* a b))
|#
(read-sandbox-file #P"/tmp/plugin.lisp")
;;
;; caught COMMON-LISP:STYLE-WARNING:
;; The variable C is defined but never used.
;;
(#<FUNCTION (LAMBDA (#:X)) {10068B008B}>
#<FUNCTION (LAMBDA (#:A #:B #:C)) {10068D484B}>)
Nothing above is "impossible" to do with other languages. The plug-in approach in Blender, in music software or IDEs for statically compiled languages which do on-the-fly recompilation, etc. Instead of external tools, dynamic languages favor tools which make use of information that is already there. All the known callers of FOO? all the subclasses of BAR? all methods that are specialized by class ZOT? this is internalized data. Types are just another one aspect of this.
(see also: CFFI)
Best Answer
I think the Article has a point as far as JavaScript vs. CoffeScript is concerned.
I personally find JavaScript quite readable and I just do not see the point of sticking another layer of syntax on top.
I have similar experiences with Java/Groovy, Groovy is just great: highly expressive, cuts out a lot of useless tedious typing compared with Java, the "extras" like native SQL support are really worth having. BUT the last time I used it debugging was painful, you end up stepping through endless obscure internal Groovy classes before you get back to your own code.
Python on the other hand is a complete self supporting environment, it is it's own language and is not tacked on top of another language (although Python itself is written in C and has excellent integration with anything written in C or C++). It has its own debugger so for the most part you are debugging the python code you wrote.
The designers of Python obsess over the expressiveness of the language and consistency of syntax. Once you get the hang of it it is very readable. You genuinely write much less code in Python compared with using other languages to solve the same problem, and, well written Python code is clear and unambiguous.
The only downsides are that in common with most dynamic languages it does not play well with IDEs, and, all that lovely high level expressiveness is not interpreted into a lean mean execution.