Hacker Newsnew | past | comments | ask | show | jobs | submit | adityaathalye's commentslogin

Post author here. I'm following the global #AWS outage. #HugOps to the people there, and everywhere restoring service.

Complexity is what it is...

However, I feel we as software people---executive, product, design, engineering, the whole nine yards---ought to think systematically in terms of Software Debt, as software organisations.

No more "technical" debt, as in "bad code" debt.


If the language allows passing lists of functions, then `comp` can be implemented by hand: https://clojuredocs.org/clojure.core/comp

And re-implementing `comp` by hand can teach us more than we bargained for (all the way to compiler technology)... I blogged about it here: https://www.evalapply.org/posts/lessons-from-reimplementing-...

  ;; Clojure source code for `comp` (since Clojure v1.0)
  (defn comp
    "Takes a set of functions and returns a fn that is the composition
    of those fns.  The returned fn takes a variable number of args,
    applies the rightmost of fns to the args, the next
    fn (right-to-left) to the result, etc."
    {:added "1.0"
     :static true}
    ([] identity)
    ([f] f)
    ([f g] 
       (fn 
         ([] (f (g)))
         ([x] (f (g x)))
         ([x y] (f (g x y)))
         ([x y z] (f (g x y z)))
         ([x y z & args] (f (apply g x y z args)))))
    ([f g & fs]
       (reduce1 comp (list* f g fs))))


Oh and, the arrow-kt library bolts this onto kotlin.

Utilities for functions: https://arrow-kt.io/learn/collections-functions/utils/



With telecom, we benefited from skipping generations. I got into a telecom management program because in 2001-ish, I was passed by on a village street by a farmer bicycling while talking on his cellphone. Mind you my family could not afford cellphone call rates at the time.

In fact, the technology was introduced out here assuming corporate / elite users. The market reality became such that telcos were forced kicking and screaming to open up networks to everybody. The Telecom Regulatory Authority of India (back then) mandated rural <> urban parity of sorts. This eventually forced telcos to share infrastructure costs (share towers etc.) The total call and data volumes are eye-watering, but low-yield (low ARPU). I could go on and on but it's just batshit crazy.

Now UPI has layered on top of that---once again, benefiting from Reserve Bank of India's mandate for zero-fee transactions, and participating via a formal data interchange protocol and format.

Speaking from India, having lived here all my life, and occasionally travelled abroad (USAmerica, S.E. Asia).

We, as a society and democracy, are also feeling the harsh, harsh hand of "Code is Law", and increasingly centralised control of communication utilities (which the telecoms are). The left hand of darkness comes with a lot of darkness, sadly.

Which brings me to the moniker of "third world".

This place is insane, my friend --- first, second, third, and fourth worlds all smashing into each others' faces all the time. In so many ways, we are more first world here than many western countries. I first visited USAmerica in 2015, and I could almost smell an empire in decline. Walking across twitter headquarters in downtown SF of all the places, avoiding needles and syringes strewn on the sidewalk, and avoiding the completely smashed guy just barely standing there, right there in the middle of it all.

That was insane.


That kind of extreme poverty juxtaposed to extreme wealth, and all of the social ills that come along with it, have always been a fixture of the American experience. I don’t think it’s a good barometer or whether the USA is in decline when there has long been pockets of urban decay, massive inequality, drug use etc. Jump back to any point in American history and you’ll find something similar if not much, much worse. Even in SF of all places, back in the wild west era gold rush or in the 1970s… America has always held that contradiction.


Yeah, I sort of recounted a stark memory. That juxtaposition was a bit too much.

However, it wasn't just that, and the feeling has only solidified in three further visits. It isn't rational, very much a nose thing, coming from an ordinary software programmer (definitely not an economist, sociologist, think tank).


I really tried hugo, but I gave up because of hugo's many annoyances --- breaking changes in versions a mere few months apart (why????), yet another arbitrary templating system, poor support for org-mode out of the box, lots of impedance mismatch with ox-hugo (a valiant effort), runs a local server for local development, injects javascript for live refresh, etc...

Don't get me wrong, it is a really nice project which I do recommend to people who don't want to go down the path of writing their own custom site maker... The single-binary formula allows hugo to offer a much better set of trade-offs than the competition.

But... if you can write your own, write your own. It is a glorious yak shave.

My only tip will be to avoid all dependencies like the plague. For stability and sanity.

The upshot... After over two years of using my dinky-ass handmade pandoc-usin' (not even parallelised) static site maker, I feel hugo is not even as fast as what I have.


> breaking changes

Yeah, that's bitten me and it's super stupid. At this point, I've just pinned hugo so I don't update it any more. It's a friggin' static site with basically no Javascript (just a little for the site search feature—handled by the theme) so I don't feel any need to keep Hugo up-to-date.


How do you implement live refresh without JavaScript?


inotifywait -> pandoc compile -> xdotool -> browser action :)

I get the computer to hit F5 on the browser (and/or type URLs into the url box and hit enter).

Here is how it works (and it works great!): https://github.com/adityaathalye/shite?tab=readme-ov-file#ho...


Hah! Superfriend!

First... Love your site (clean, fast, easy on the eyes, no need for JS to read). And your writing... yours is a proper blog. I used to feel bad about not being able to "just blog" like a real blogger, but I discovered that what I really like, is to write, in order to think. So, my blog has become part of my Big Reason to write (a lot) locally, and I am very happy to publish giant-ass blog posts; longform thinking.

Second... I went down a very similar path to custom site-buildin'.

Reject Wordpress because it's the 2020s -> reject anything mandating npm, gem, pip, lockfile web-scale dependency madness -> just hugo (single binary, wow) -> hugo + ox-hugo -> ouch, yet another custom templating language, and no backwards compatibility -> should I just Wordpress like it's 2005? -> NO, wait. Now I know programming. -> Voila! `shite` [1] (org-mode content -> pandoc -> plain HTML-and-CSS website [2]).

[1] https://github.com/adityaathalye/shite (dicussed here, that one time: https://news.ycombinator.com/item?id=34486596)

  Show HN: Shite – little hot-reloadin' static site maker from shell
  141 points by adityaathalye on Jan 23, 2023 | 60 comments
(The discussion will answer anyone's burning question about the project name :)

[2] https://evalapply.org

Third... Again... superfriend! 10000% same sentiment as yours:

> that takes exact same files and produces output that I fully understand e2e, becoming the project I'm most proud of

See my `shite`'s incredible documentation---animated GIFs and everything. Probably my second-best documented personal project (or tied for first-best with clojure-multiproject-example).

Things that give me inordinate joy:

- `shite` weighs in at ~300 Lines of Code (and why does it have 240 Github Internet Points, who are these insane people???)

- it is truly "serverless" - I don't run a local dev server even

- it hot-compiles and hot-refreshes on save - fully interactive local authoring (as well as live template modifications)

- since Feb 2022, it broke (only very slightly), after I distro upgraded Ubuntu 22.04 LTS to 24.04 LTS, because pandoc changed its default handling of line breaks, breaking layout of hand-indented "verse" text.

- Under 10 second full site rebuild, with 43 posts totalling over 100K words and over 40 more auto-generated pages (rss feed, various xmls, and per-tag blog post index pages). And I haven't even made it parallel yet. Probably will, if full rebuilds get longer than 30 seconds.

- The resulting site scores top marks on lighthouse and even image-heavy pages render fully in under a second on 4G mobile internet. (zero analytics, or tracking javascript).

- And my most favourite part: I've made Internet Friends because of the site! https://www.evalapply.org/about.html#standing-invitation

It's hilarious --- I've done such sophisticated work for work, but this little piece of personal software is my pride and joy... It makes me grin almost every single day.

May The Source be with you too! _\\ // (yes, I love mixing metaphors)


Ditto. I wanted to show JavaScript text art animation, and could "just" do this:

  *** ~setInterval~ and ~setTimeout~ worked just right
  These let us call functions that do exactly the thing we want,
  viz. punch /[[#the-aesthetic-of-text-art-and-its-animation][characters]]/
  into our "live spreadsheet" medium, exactly the way the artist
  placed them in the original art source.

  These methods can make a CPU sing, but hey, the awesome art
  is worth every watt it, ah, draws.

  #+html: <div class="box invert">
  #+html: <em>Random twitch loop <code>setTimeout</code> and recursion.</em>
  #+html: <div id="blink-demo"></div>
  #+html: </div>
  #+html: <script type="text/javascript">demoBlink();</script>

  #+html: <div class="box invert">
  #+html: <em>Flipbook-like frame-by-frame animation loop with <code>setInterval</code>.</em>
  #+html: <div id="glider-demo"></div>
  #+html: </div>
  #+html: <script type="text/javascript">demoGlider();</script>
This works very nicely because I've structured my website as "every post is just a microsite". See:

src: https://github.com/adityaathalye/shite/tree/master/sources/p...

  \_ (develop %|u+4) $ tree sources/posts/animate-text-art-javascript/
  sources/posts/animate-text-art-javascript/
  ├── animations.js
  ├── blink.ddw
  ├── DarkDrawSheetView.png
  ├── glider.ddw
  ├── HanukkahOfData2022ArtCopyrightDwimmertxt.png
  ├── HanukkahOfData2022ArtSliceCopyrightDwimmertxt.png
  ├── HanukkahOfData2022DarkDrawDrawingViewCopyrightDwimmer.png
  ├── HanukkahOfData2022DarkDrawSheetViewCopyrightDwimmer.png
  ├── index.org
  ├── loading.ddw
  └── spinner.ddw
  
  1 directory, 11 files


#+html works, but why not just a proper HTML source block? Easier to edit, and you get syntax highlighting?


Yeah, that post was before I realised there's a better way. Now I use a proper source block with export control etc.


The neat thing about org-mode for writing and publishing (I don't use it for "productivity") is that every time I have a new requirement, there is a solution that I can integrate into my existing writing workflow. And I get multimedia publishing "for free".

Discussed here: https://news.ycombinator.com/item?id=43157672

  Why and How I use "Org Mode" for my writing and more
  217 points by sebg 7 months ago | 64 comments
src: https://github.com/adityaathalye/shite/blob/master/sources/p...


So much this. Warts = (software longevity) life lessons. (Though it must be noted that warts != bad design.)

Some years ago, I gave a talk on functional-style shell programming which began with this:

  Prelude: Why even bother?

  Personally…

    Text is everywhere, better learn to process it
    The masters already solved it better
    Stable tools, well-known warts
    Personal/team productivity, tool-building autonomy
    To learn about
        good and successful design
        bad and successful design
        computer history
    For the fun of it

ref:

Dr. Strangepipes Or: How I Learned To Stop Worrying && Function In Shell (Functional Conf 2019)

org-mode slideware: https://gist.github.com/adityaathalye/93aba2352a5e24d31ecbca...

live demo: https://www.youtube.com/watch?v=kQNATXxWXsA&list=PLG4-zNACPC...


```quote

Sontag is strongly averse to what she considers to be contemporary interpretation, that is, an overabundance of importance placed upon the content or meaning of an artwork rather than being keenly alert to the sensuous aspects of a given work and developing a descriptive vocabulary for how it appears and how it does whatever it does.

```


OP here. Ordinarily, I would agree with you, because PageObjects themselves are not composable, in languages belonging to the "Kingdom Of Nouns".

However, the following design, thanks to Clojure's language design, helped address a rather nasty situation.

A tightly scoped Domain Specific Language, over some Types of PageObjects, all of which compose arbitrarily (without breaking value semantics). So, if you wanted the `value` of a Modal box having all sorts of switches, form fields etc., you'd call `value` on it, and it would call `value` on all of its constituents, and return the immutable hash-map snapshot of whatever state it found.

  Cross-cutting concerns

  | v PageObject / DSL -> | open | close | open? | select | deselect | ... |
  |-----------------------+------+-------+-------+--------+----------+-----|
  | Dropdown              |      |       |       |        |          |     |
  | Checkbox              |      |       |       |        |          |     |
  | Switch                |      |       |       |        |          |     |
  | Modal                 |      |       |       |        |          |     |
  | SearchList            |      |       |       |        |          |     |
  | ...                   |      |       |       |        |          |     |
Concrete example (in the deck and demo linked below):

  (defprotocol IPageObject
    "Each PageObject MUST implement the IPageObject protocol."
    (page-object [this])
    (exists? [this])
    (visible? [this]))
And then an implementation like this:

  (defrecord Checkbox [target-css]
    IPageObject
    (page-object [this]
      this)
    (exists? [this]
      ;; webdriver check if target-css exists
      )
    (visible? [this]
      ;; webdriver check if target-css is visible
      )

    Selectable
    (select [this]
      ;; webdriver select the target
      )

    (deselect [this]
      ;; webdriver undo selection
      )
  
    (selected? [this]
      ;; webdriver return true if target selected
      )  

    Value
    (get-value [this]
      ;; webdriver return current selection state
      (selected? this)))
Deck: https://github.com/adityaathalye/slideware/blob/master/desig...

Talk + Demo: https://www.youtube.com/watch?v=hwoLON80ZzA&list=PLG4-zNACPC...

I also commented about it here: https://news.ycombinator.com/item?id=45161410 (Clojure's solution to the Expression problem).

That said, UI testing is a hot mess in general (especially for SPAs). I prefer to avoid automating anything but the "happy paths". IME, exploratory testing is better at sussing out corner cases, and "emergent" misbehaviours. So I do that, in addition to the "happy path" suites. Cue: James Bach et. al. https://www.satisfice.com/

Also I am warming up to server-generated HTML, because I can unit-test that, if I can use `hiccup` syntax + HTMX. In that case, I just make all request handlers spit out HTML fragments as Clojure data, and test those responses in my test suite.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: