More from Paolo Amoroso's Journal
<![CDATA[My journey to using and programming computers started around 1983 with a Sinclair ZX Spectrum 48K, the very first I owned. At the time I was clueless. For example, I wondered whether, once I loaded a program from tape, I needed to write it back at the end of the session so that it didn't vanish when turning off the machine. The Sinclair ZX Spectrum Introduction and the Sinclair ZX Spectrum BASIC programming guides that came with the device were my first learning resources, complemented by the great Italian computer magazine MC-microcomputer. Aside from some books, in that pre-online era technical documentation wasn't easy to come by in Italy, especially foreign works in English. I pored over the Spectrum manuals, reread them many times, and experimented with the sample code. I've never been into gaming but did run many games to see what the machine could do. I've come a long way since then, hopefully. #retrocomputing #personal a href="https://remark.as/p/journal.paoloamoroso.com/the-origins-of-my-computing-journey"Discuss.../a Email | Reply @[email protected] !--emailsub--]]>
<![CDATA[GravityLoops, my gravity simulator in Interlisp and LOOPS, can finally show something on the screen. The program now animates a body of mass like the Moon interacting under gravity with a body of mass like the Earth. The dots in the simulation window here are the bodies after 180 days of simulated time, with the Earth at left. Watch the full run. Screenshot of a still frame of a simulation of a body like the Earth and one like the Moon interacting under the muatal gravity. Well, that's not much. But the code confirms the simulation loop with an offscreen buffer works well. After putting in place some infrastructure, to get there I wrote the simulation loop, tweaked a few methods, wrote a demo function that sets up the simulation, and fixed a few bugs. There's a lot more to do. I need to make the graphics of the body markers more complete and explanatory, control the speed of the animation, fix more bugs, and refactor to decouple some interclass dependencies. And, of course, GravityLoops will also have a user interface to control the simulation and enter the parameters. #GravityLoops #Interlisp #Lisp a href="https://remark.as/p/journal.paoloamoroso.com/early-simulations-with-gravityloops"Discuss.../a Email | Reply @[email protected] !--emailsub--]]>
<![CDATA[I started working on the class Universe of GravityLoops, my gravity simulator in Interlisp and LOOPS. I defined the class itself and the main methods, Universe.Register and Universe.Simulate. The class represents a collection of bodies and manages the parameters and state of the simulation. Universe.Register adds a body to a universe, Universe.Simulate runs the simulation. In the C++ code of the article my design draws inspiration from, an instance variable of the class UNIVERSE holds a pool of bodies in an array, with the most recently added body indexed by another instance variable. In GravityLoops the corresponding instance variable bodyPool is a list which, as the article notes, is more versatile and doesn't need the index. Universe.Simulate, just a stub for now, is the core method. It will update the state of the simulation, display the bodies in a graphical window along with status information, and check whether the user interrupts the simulation. The C++ program runs the simulation until the user presses a specific key and GravityLoops will have a similar feature. I'll also have the program accept a number of time ticks to step the simulation through. For Universe.Simulate I'll mostly follow the C++ code. But I plan to revisit the decision after I have something running to experiment with. I may want to split the simulation functionality into more than one method to separate the simulation itself from output, or redesign control around LOOPS' active values. #GravityLoops #Interlisp #Lisp a href="https://remark.as/p/journal.paoloamoroso.com/representing-the-universe-of-gravityloops"Discuss.../a Email | Reply @[email protected] !--emailsub--]]>
<![CDATA[I started working on GravityLoops, a software that simulates a collection of bodies interacting under the mutual gravity. I develop it on Medley in Interlisp and its object extension LOOPS, the Lisp Object-Oriented Programming System. GravityLoops will show an animation of the bodies and their motions, along with facilities for defining the parameters of the system and controlling the simulation. Motivation I've been meaning to do a LOOPS learning project but none of the ideas I initially came up with clicked. I wanted something more complex than a toy but easy enough to implement with reasonable effort. The project should also incorporate naturally the features of LOOPS, such as the gauges library of graphical meters and dials for displaying quantities. I finally stumbled upon the gravity simulator described in the article Force-Based Simulations by Todd King in the September, 1989 issue of Dr. Dobbs Journal. It's just perfect. I'm adapting to LOOPS the design of the sample C++ code that comes with the article. It's nice as it reads like an object-oriented domain specific language for simulation. The code is so short and clean I can fully understand it despite my minimal C++. I never thought I would say that of C++. There is much to like of King's program starting from its domain, astronomy and physics, which overlaps with some of my passions. The project is period accurate too as when Dr. Dobb's Journal published the article LOOPS was still under development. And, along with window systems, simulation was among the killer applications object-oriented programming proponents pointed to. The program comprises only two, hierarchically unrelated classes, a shallow inheritance design more in line with the later evolution of object-oriented programming. But the application does offer other potential classes that are a good fit for LOOPS. For example, I plan to specialize the LOOPS class Window to represent the simulaton window. I will likely need more classes for the GUI, such as dialogs for entering the simulation parameters. LOOPS is one of the subsystems best integrated with the Interlisp environment and comes with good documentation. I want to experience this high integration, the ability of combining tools designed to work together that comes natural once you're familiar with the environment. Adapting King's program to the Interlisp environment is also an opportunity to employ useful programming techniques like screen buffering to improve animation fluidity. Plus, anything that draws pretty graphics is fun. Design To adapt Todd's design to LOOPS I create matching classes with similar instance variables and methods, named according to the LOOPS style. I will rename a few confusing methods, such as UNIVERSE::service() to register a body with a universe which I'll call Universe.Register, and UNIVERSE::big_bang() to run the simulation which will become Universe.Simulate. The C++ code represents a 2D vector as a struct that I map to an Interlisp record. A class seems overkill. Todd's program outputs to the MS-DOS text console via the conio library. GravityLoops instead will draw graphics in a window. So far the code implements the Body class that represents a body. I'm about to start working on the Universe class that holds a collection of bodies and manages the parameters and state of the simulation. Once the core classes are in place I will turn to implementing the animated simulation. #GravityLoops #Interlisp #Lisp a href="https://remark.as/p/journal.paoloamoroso.com/gravityloops-a-gravity-simulator-in-interlisp-and-loops"Discuss.../a Email | Reply @[email protected] !--emailsub--]]>
<![CDATA[Insphex adds the Hexdump item to the File Browser menu to view the hex dump of the selected files. The initial implementation called the public API for adding commands at the top level of the menu. To later move the item to the See sumbenu that groups various file viewing commands I resorted to list surgery, as the API doesn't support submenus. The problem is internal system details can and do change, which happened to the File Browser menu and led to an Insphex load error. I fixed the issue by reverting the public API call and now the item is back at the top level of the menu. Insphex is a hex dump tool similar to the Linux command hexdump. I wrote it in Common Lisp on Medley Interlisp. #insphex #CommonLisp #Interlisp #Lisp a href="https://remark.as/p/journal.paoloamoroso.com/rearranging-the-file-browser-menu-for-insphex"Discuss.../a Email | Reply @[email protected] !--emailsub--]]>
More in programming
I’ve been taking a break from Mastodon as my social home on the web for about six weeks. It has been more difficult than I’d usually admit. I have an amazing local community in my town that I love and am deeply involved in. But nobody here is a programmer, or even a computer nerd, so it doesn’t serve my need for a tech community. I work alone, for myself, in my house. It’s a fortunate lifestyle with many upsides, but it means I don’t get that form of community at work, either. I’ve had this feeling before… as a teenager in the 1990s. It’s profoundly lonely. But when I got internet access, that started to change. I found my people. First in the Total Annihilation community (RIP, Annihilated), then the HardOCP Forum, then the Something Awful Forums, then Tumblr, then Twitter and our community of Apple bloggers, and then Mastodon. Communities form, change, and dissolve over time. None of those are, today, anything like what they were when I most enjoyed them. We change, too. I didn’t move on from most of those solely because they changed — it was usually because we both changed, and it was no longer a good fit. My break from Mastodon has been a relief in some ways, as I’ve felt increasing divergence between what I wanted and what I was getting from it, but I didn’t know where else to go. Instagram, TikTok, and YouTube are all more video-broadcast platforms than communities. All I’ve found on Bluesky is even more anger and politics, the last things I need or want. Threads hasn’t yet stuck for me, and it’s owned by an asshole. Twitter was an amazing product and community that was previously owned by assholes, and now it’s X, which has a strong but different tech community, and is owned by different assholes. So I’ve just been… nowhere, for the first time since the 1990s. It has been, once again, quite lonely. Sure, it’s been relaxing, too, but in the way a vacation is relaxing. It’s great to take breaks, but after a long vacation, I’m ready to turn my brain back on. Without participating in a large, broad tech community, I’m exposed to fewer new ideas, both of my main jobs (app development and podcasting) are much harder, the quality and reach of my work have suffered, my skills aren’t improving as much, my mind is less stimulated, and I feel disconnected from my professions and passions. My world has gotten smaller. I could keep going like this to prove a stubborn victory or purity test, but I’d mostly just be hurting myself. Communities change, conditions change, and we change. We’re all better off if we’re willing to change our minds, and if our communities let us, no matter how strongly our younger selves declared a previous position. So I’m going to wade back in and see how it goes, trying to find a better balance to hopefully have better results, including on Mastodon. My people are spread across multiple services, and I’m going to explore them all, despite most of them being owned by assholes. I’d love to participate in communities without any assholes benefiting from it, but in the modern world, that simply isn’t possible. The only alternative is to isolate myself and not have a community at all (or a job, or a smartphone, or a computer, or internet access, or a car, or most of my food, or my country). That’s neither a price I’m willing to pay nor a condition I’d try to impose on anyone else. I’d love to have your support, forgiveness, and grace as I try to find my people again, and I strive to offer the same to all of you. Everyone deserves to be part of a community. And as I grow, I’m learning to declare fewer absolutes in a complex, imperfect, and constantly changing world.
My now-traditional “summary” of the conference along with my own commentary and thoughts.
Every year, browser vendors collaborate via the Interop project to synchronize their efforts on new HTML/CSS/JS features. This year, there’s a ton of super exciting features being considered! In this blog post, we’ll explore the CSS of the future, to get a glimpse of what we’ll soon be able to do.
Imprint’s average engineer is merging 4x more PRs than 2 years ago. Yay. Aggregated behind the average is something even more interesting: we have two teams that are merging 10x their PRs over that period. One engineer is merging 25x the PRs per week of our average engineer two years ago, and a number are merging 10x. That’s pretty neat, and the slope of the line suggests our average in a year is going to look much closer to today’s p90 than today’s p50. Even more importantly, we aren’t just shipping more, our quality has improved: incidents are down 42% half-over-half, and critical incidents are down 78% half-over-half. I think we’ve always known the quality/velocity tradeoff wasn’t a particularly useful construct, but that’s undeniable today. As we’ve walked this path, we–like everyone else progressing down it–have run into the problem of pull request review. The p50 pull request review took about 33 minutes to complete 2 years ago, but now takes us about 77 minutes. The slope here correlates tightly with the number of pull requests getting merged. Tightly enough that addressing it became one of my priorities for the week. We solved it! Just kidding, we’ve absolutely not solved it, but I think our current approach is an interesting one, which we call the small-change. The work discussed here was shaped and done by many folks at Imprint including Dan, Joy, Daniel, Lenny, Taylor, Ted, and Annie, among many others. Why review pull requests? There are four reasons we review pull requests: Knowledge sharing between author and reviewer – software engineering is generally learned via apprenticeship, and reviews are a primary mechanism of experienced engineers teaching others what good software looks like. We believe the current volume means that this knowledge sharing will have to move towards operating on clusters of pull requests, rather than individual pull requests Preventing errors – review has always been an expensive time to catch errors, and we believe that effective CICD along with harness verification techniques like poteto’s pstack are more effective mechanisms for preventing errors than review Preventing malicious behavior – my experience is that even careful code review will generally miss competent malicious behavior, although fortunately most malicious behavior is incompetent. We believe both sorts of behavior are best identified using a combination of fixed rules (modifying these specific objects/classes/files requires review), anti-abuse mechanisms that we’ve refined in our LLM-based member support experiences, auditing, and audit log inspection Compliance obligations in our documented controls – these can be changed, but today they require that an independent human reviews changes in a subset of our repositories In the modern development paradigm, we think there is a better solution for each of these problems. But, we also want to make these changes very cautiously. Small steps with small-change We believe we move fast by finding narrow, contained ways to validate new practices, so to iterate our way into an effective solution, we’ve developed the concept of a small-change. Here’s how it works: When a pull request is marked ready, CICD determines whether it is eligible to be a small-change. This is represented as a passing Github check. There is also a label for visibility, but it is the check itself, managed by the build and not human modifiable, that determines eligibility. (The label is used for initial filtering, but the check is still independently verified.) Something is a small-change if it meets all of these criteria: It is less than 1,000 lines of code There are no p1 or p2 findings from our ai-code-review automated review bot The author has “experience” in the service or application, defined as 10+ prior merged pull requests into that service or application’s directories. For changes working across multiple services or applications, the author must have experience in all of them to qualify Impacts fewer than N distinct services or applications. N is 1 on our frontend monorepo, and N is 3 in our backend monorepo, where typical changes will modify both a gRPC service and a common HTTP gateway Shared libraries and utilities files are not eligible for small-change Each repository has a .small_change file which allows per-path customization while we continue to tune the behaviors. For example, a service dealing with money movement can be excluded Our Slack automation tags every reference to a pull request with reacji labeling the state of that pull request, for example if it has failing tests, if it has been approved but tests are still running, or if it is ready to merge. We added a small-change reacji that indicates which of those pull requests meet the small-change criteria In our internal skills repository, we created two skills that have been distributed across harnesses: review-small-change which takes a list of repositories and reviews all open, non-draft, small-changes, including providing approval if they meet the review’s criteria (all checks pass including small-change check, and not touching on sensitive topics such as payments and security) review-pr-cluster which reviews batches of pull requests to identify common themes that came up, and suggest opportunities for discussion and adding verifications We set the social expectation that any error caused by a small-change is a failure in our system, and has to be solved at the system level: improvements to ai-code-review, to our verification mechanisms, to our CICD, to our harness, etc. This took about two days of infrequent attention to implement and rollout, although I imagine we will be tuning the knobs here for a long time. Maybe forever. fleet: centrally orchestrated harness I’ll briefly mention our other approach to reducing code review volume, which anchors on our centrally-orchestrated harness, fleet. (Which is similar to Stripe’s Minions although not following the one-shot approach in particular). We rely on fleet to implement and verify software in a highly controlled harness running in the cloud, with independent evaluation mechanisms to identify the correct number of independent reviewers for any given change. That number can be as low as one (e.g. fleet writes, one human reviews) for changes evaluated as safe. Results / next steps / reception I’ll be honest, it’s too early to give a useful result here. From early results, about 10% of changes qualify as a small-change. Those are now eligible for very fast approval, and generally get it unless they trip a flag, generally due to touching a security or money adjacent topic. While 10% is a small percentage, the core concept here is working, and ultimately will succeed or fail based on our ability to expand that percentage over the next few months in tandem with expanding our verification mechanisms to be increasingly comprehensive. This is ultimately going to fail or succeed depending on our ability to improve our verifications, which does require more difficult sorts of techniques to accomplish in low scale-complexity, high domain-complexity software than in the high scale-complexity, low domain-complexity products where many techniques like incremental rollouts are exceptionally effective. (Don’t get me wrong, they still work, they just provide less coverage when most users have different configuration and behavior.) Folks have not been uniformly excited about this, it’s a substantial change from how we’ve learned to be good engineers, and it’s uncomfortable to reevaluate whether a long-held best practice has become merely dogma. The most energizing part of the current cycle is that we get to reevaluate these practices we grew up on every week; the most painful part of the current cycle is that we’re likely to fall behind if we ever stop reevaluating them.