Google Bard and Emacs
After reading a Google blog post on Bard's increasing ability for reasoning about source code, I thought I would give it a try. The issue is that not like OpenAI, Bard currently does not have an http API that I can use via curl. I googled around and came across the `bard-rs` project here: https://github.com/Alfex4936/Bard-rs. So I followed the excellent instruction to get set up using bard from command line and its is pretty solid. I used following Elisp to use `bard-rs` from Emacs' compilation buffer here:
(defun kcompilation-start (cmd name &optional mode) (let* ((compile-command nil) (compilation-save-buffers-predicate 'ignore) (compilation-buffer (compilation-start cmd (if (equal mode 'read-only) nil t) (lambda (m) (or (when (boundp 'name) (format "*%s*" name)) (buffer-name)))))) (when current-prefix-arg (with-current-buffer compilation-buffer (switch-to-prev-buffer (get-buffer-window (current-buffer))))) (message (format "Running %s in %s ..." cmd name)))) (defun kprompt-bard (&optional p) "Prompts for input to send it to `bard` using `bard-rs` in *bard-prompt* buffer. If mark-active, uses the text in the region as the prompt" (interactive "P") (let* ((bs "bard-prompt") (bname (format "*%s*" bs)) (bname (if (get-buffer bname) bname (progn (kcompilation-start "bard-rs -e ~/.env" bs) bname))) (prompt (if mark-active (replace-regexp-in-string "\n" "" (buffer-substring-no-properties (region-beginning) (region-end))) (read-string "AI Chat Prompt: ")))) (with-current-buffer (pop-to-buffer bname) (when p (end-of-buffer) (insert "!reset") (comint-send-input) (end-of-buffer) (insert prompt) (comint-send-input)) (when (not p) (end-of-buffer) (insert prompt) (comint-send-input)))))
You can bind `kprompt-bard` to any key of your choice and start interacting with Google bard from the comfort of Emacs' buffer.
AI or not to AI
1913 Webster dictionary gives following definition to Artificial Intelligence: Artificial - 1. Made or contrived by art; produced or modified by human skill and labor, in opposition to natural; 2. Feigned; fictitious; assumed; affected; not genuine. 3. Artful; cunning; crafty. 4. Cultivated; not indigenous; not of spontaneous growth; Intelligence - 1. The act or state of knowing; the exercise of the understanding. 2. The capacity to know or understand; readiness of comprehension; the intellect, as a gift or an endowment. 3. Knowledge imparted or acquired, whether by study, research, or experience; general information. Specifically; (Mil.) Information about an enemy or potential enemy, his capacities, and intentions.
Let us read and re-read above definitions and give it a few minutes to sink in. With our skilled labor, we have managed to produce a very powerful fictitious software that can understand, produce and reason about human generated artifacts such as language, images and videos. Our ability to make it more scalable, more accurate and more controllable is just a matter of time considering what we have is already pretty powerful enough. My following interaction with ChatGPT 3.5 is already impressive:
[ME]: Explain, then add tests and simplify if possible: (defun kprompt (&optional p) (interactive "P") (let* ((bname (if p "*org-ai-on-region*" "*scratch*")) (directive "Explain, then add tests and simplify if possible:\n") (prompt (if p (buffer-substring (region-beginning) (region-end)) (read-string "AI Chat Prompt: ")))) (with-current-buffer (pop-to-buffer bname) (when p (erase-buffer) (org-mode) (setq truncate-lines nil) (setq word-wrap t) (org-ai--insert-created-timestamp) (insert "\n") (insert "#+begin_ai\n" "[ME]: " directive prompt "\n" "#+end_ai\n") (forward-line -1) (org-ai-complete-block)) (when (not p) (beginning-of-buffer) (open-line 2) (org-ai-prompt prompt))))) [AI]: This function takes an optional argument, p, which determines whether the user will be prompted to enter a text or whether the function will use the text highlighted in the buffer. If p is provided, it will create a new buffer with the name "*org-ai-on-region*" and insert the highlighted text from the current buffer along with a directive. This new buffer buffer will be formatted using org-mode to allow for better organization of comprehension text. Finally, it will call org-ai-complete-block to add some AI-generated text to the prompt. If p is not provided, it will prompt the user to enter text and then call org-ai-prompt org-ai-prompt to add some AI-generated text to the prompt. Tests: Input: (kprompt) Expected Output: AI Chat Prompt: Input: (kprompt t) Expected Output: *org-ai-on-region* buffer created with prompt Input: (Highlight "This is a test") (kprompt t) Expected output: *org-ai-on-region* buffer created with "This is a test" text and AI-generated text. Simplified Code: The code appears to be relatively straightforward and efficient. No simplification is needed.
It understood and reasoned about a piece of code (simple for now but does not matter as it can get pretty powerful in no time) despite the fact that it has never seen above code before in its entirety (I am pretty sure about that since it is a private code and this is the only time I am making the code public). This degree of intelligence codified into a software that a few powerful cooperation currently dominates should be something that keeps every software engineers awake at night. Not because of its inherent danger or tremendous productivity boosting ability as folks on the opposite side of spectrum of current AI debate claimed, but because of the very fact that every aspect of human lives will be effected by a such a powerful code like ChatGPT whether we like it or not, and we need to do whatever we can to ensure it is used for the good of humanity in general. It is created by humans and should serve humans. Make no mistake about it. Powerful software systems like that is already used by big cooperations and rouge states to cajole people into a state of self censorship if not into a state of heedlessness of its future implication. Social media, powerful tracking and image recognition systems are already pervasive in the lives of millions of people that are being controlled by dictators all around the world (and it is being exported very actively in the name of economic progress) to socially engineer people's behaviors that benefits their agenda in the name of social and economic progress at the very expense of destroying anyone or anything that is deemed as an obstacle.
As a software engineer who have seen the worst of what bad actors can do with such a powerful systems, I am calling out to all of my fellow engineers to start thinking about what kind of world we would like our kids to inherit from us regardless of where you are, who you are and what is your geopolitical affiliation is. The wave is already there, and it takes all of us to make sure we are not being social engineered out of our humanity. I believe in the power of our humanity to make AI to work for us not the other way around. I registered the domain www.codeforhumanrights.org few years ago and this might be a good time to start putting it to a good use. If you are reading this and feel the need to start doing something, reach out to me via ktuman at acm dot org.
Atomic commits made easy
Code complexity is something we all deal with in our daily work. There are many tools to helps us manage it. One of the most important one is to make incremental changes where each change is about one and one context alone , which is a great definition of an atomic commit. I do not think I need to convince you about its benefits any further than what I already have alluded to above, which is worth repeating here: It helps us contain complexity within our code base. In pursuit of making it easy for me to do atomic commits, I settled down following workflow:
- Separate changes by its effects. If a change is immutable, that is to say it is simple refactor or restructure that does not change the existing behavior, it should be in one commit.
- If changes are mutable, that is to say it changes existing behavior, group them further by their logical context where the context is about one and one thing alone. This is really crucial since we would like to make sure every commit can stand on its own and does not depend on later commits. This gives us the linear append only change that we can easily keep track of. This might sound a bit strange to you, but it means that you should not commit a not finished work at least not push up stream. That also does not mean that you should not commit your work as often as possible but if you do commit and end up violating above convention, you should amend/squash your commits.
Having armed with above convention, I incorporated following tools to help me to make atomic commits easy:
I am not going to repeat what the excellent blog talked about above tools here, but it is worth checking it out, and I highly recommend it. If you happen to use Emacs, here is how you add it to your config:
;; clone above repo in to ~/repos and eval following code (load-file "~/repos/commit-patch/commit-patch-buffer.el") (eval-after-load 'diff-mode '(require 'commit-patch-buffer nil 'noerror))
With above configuration, you can M-x vc-diff a file (vc-root-diff for whole project) then kill, split or edit the resulting hunks using diff mode's built-in commands and to then hit C-c C-c to commit the patch. Later if you realized that your commit is not atomic, you can make further changes and amend previous commit by C-c C-C (note the upper case C).
Notes on StrangeLoop 2022
StrangeLoop this year made me feel almost as normal as those during pre pandemic times especially in terms of size of participants and sponsors. I actually believe it had the most sponsorship so far among those I attended over the years. One noticeable company was AWS that a friend of mine joined earlier this year. So it was pretty exciting to meet up with him there. As always, the breadths of folks and topics from all walks of Software Engineering is just excellent this time as well. I took few notes on the talks that I am able to attend and would summarize them on few categories below.
Dev Experience : I consider observability to be an important part of development experience, which is always pushed back as an afterthought for almost all the startups that I worked with and I know of. The talk "Building Observability for 99% Developers" by Jean Yang just resonated with me and I am really glad that her company is building tools to make developer experience better using eBPF that has matured in the last few years. It was quite and entertaining talk and I highly recommend you check it out. Another talk that I really enjoyed is "Workflows, a new abstraction for distributed systems" by Dominik Tornow. If you are dealing with the chaos of distributed services, the abstraction that he presented make you feel like you are working with monolith (oh the happy times :) again with the advantage of cloud scalibility.
Programming Languages : I personally prefer dynamic languages (Clojure to be exact) as my tools of choice for my day to day practice of solving problems for people but I do see the benefit of type system as a guiding rail when designing an API or better yet generating code. You should check out the talk "Codegen with Types, for Humans, by Humans" by Matthew Griffith, where he talks about how to use types to generate code for human consumption. If you are working with (or say fighting with) type system that is complecting your business logic/code execution, you should check out the talk "Monad I Love You Now Get Out Of My Type System" by Gjeta Gjyshinca, where she talks about the platform that helps Scala developer to get their type system out of business logic with just five extra characters, @node, with a compiler plugin.
Data Centric Problem Solving : Strange Loop Conf have always been attractive to data centric practices and paradigms and this year was no different. There are many talks related to how to generate, architect and analyze data. The talk titled "Data-driven investigation in defense of human rights" by Christo Buschek is presented with very clear and methodical approaches to solve real problems we face around the world. I really feel like we need more of that type of work where we put technology for the benefit of our fellow human beings. I think he should do another presentation next year titled "Data-driven investigation in defense of peace and opposition of war", which surely makes me sign up for Strange Loop for one last time (Next year will be the last time you can experience Strange Loop and I highly recommend you attend to see what you have been missing).
Automate OpenBSD anonymous public wifi log in
Security is somewhat cat and mouse game. This does not mean however you be careless or just live with what you are handed to when it comes to protecting yourself from ill-intentioned actors out in the wild. Generally, I recommend choosing security over convenience, speed or shiny features for your offline and online computing needs. To start with, you are much better protected if you start using secure defaults of the system you are using. For example, Firefox has HTTPS-Only Mode that you can enable especially if you find yourself using public wifi. If you happen to use OpenBSD, you are in a treat :). Below bash script will allow you to log in to public wifi using random MAC addresses each time you connect to it: NOTE: iwm0 is the wireless card name on my laptop and you need to replace it with yours.
#!/usr/bin/env bash ssid="$1" pass="$2" doas ifconfig iwm0 up sleep 3 echo Wireless card is up if [[ -z "$pass" ]]; then doas ifconfig iwm0 nwid "$ssid" lladdr random echo Joining public $ssid else doas ifconfig iwm0 nwid "$ssid" wpakey "$pass" echo Joining private $ssid fi sleep 3 doas dhcpleasectl iwm0 echo Renewing inet address sleep 3 echo Visiting google.com to test connection proxy=$(curl -s -L -I -o /dev/null -w '%{url_effective}' google.com) firefox $proxy