Updated: 1/17/2022
This story is a "I'm done with OOP" story.
At my day job, we have built a REST API framework in C# that we use to publish enterprise web services. The framework was designed using OO design principles and strict separation of duties, with the goal to maximize re-usability. This resulted in many "layers" in the framework, each layer becoming its own NuGet package. This resulted in a complex web of packages, where packages depend on packages which depend on packages, and caused the following problems:
That said, for all its faults, the framework is solid and provides good value. So when it was time to upgrade it to "2.0", I wanted to change the rules a bit. Here's how I got there.
A friend of mine is an FP (functional programming) enthusiast and advocate, and is internationally known in the Elixir world. I hadn't toyed much with FP since college, so when I ran into him, I started toying with various FP languages, including Elixir and Haskell.
I started taking some of the principles of FP to my day-job OO programming. The big change was a simple one: favor static methods in static classes over instance methods. This simple change meant that my functions increasingly lacked side-effects (they didn't change the state of variables in the object, or outside their scope).
If you step back and take a look at this, you'll see that what we've really done is take C# and turn it back into something closer to C (well, mostly anyway).
We applied this principle to our latest overhaul of our OO-designed product, and it has helped increase re-usability of our functions, increased testability, and has reduced bugs overall.
Here are our new "procedural programming in OO languages" principles I've adopted:
Last note: Kotlin is great for implementing these concepts. If you're in Java land, you owe it to yourself to check Kotlin out.
Posted: 12/24/21
This is an older Advent of Code solution, but the idea here was to share my solutions to some simple Advent of Code puzzles in different languages.
I like to code in Kotlin because it gives me so much flexibility: I can code in procedural, object oriented or functional styles, and I can even mix-n-match them. This isn't unique to Kotlin, for sure, but Kotlin also adds:
Enough about Kotlin, let's see the code! If you are interested in the problem, you can read it here.
import java.io.File
fun main() {
println(File("data/Day1.txt")
.readLines()
.map { s -> Integer.parseInt(s) }
.map { x -> (x / 3) - 2 }
.sum());
}
Notice that no "container" object was necessary: you can put a main function in a file and boom, go. The only "hard part" of running a small Kotlin project like this is dealing with the compilation and project dependencies, and for that you should get the Intellij IDE (more on that below).
In this example I use a function chain. First I create a new File() object. Note that I don't have to use the "new" syntax to get a new object: I just call the constructor like any other function, and I get an object back. Also note that the File() class is coming from the Java SDK, not from Kotlin. So I get to use Kotlin syntax with Java objects here.
After the object is created, I call the File.readLines() function, which returns a collection of strings (lines read from the input file). I then use the map() function to convert each line to an int, and then pipe that to another map function, where I do a little math on each integer (integer divide by 3 and subtract 2). I then pipe that list of ints to the sum function, and print the result to the screen.
If you're interested in exploring Kotlin, I suggest you just get the IntelliJ Community Edition from the JetBrains website. IntelliJ is excellent, and since I started using it, I wouldn't do Java or Kotlin without it.
You can get help on using the IntelliJ IDE, and with Kotlin, in all the usual places. It takes a little getting used to, but once you've got the hang of it, you won't want to go back.
Posted: 12/22/21
This site is hosted on Neocities, but I keep the sources in a GitHub repository. I keep it simple: I edit the code locally, check it in, and push to the main branch. A GitHub Action then kicks off and uploads the site to Neocities.
Neocities provides a simple REST API for uploading files. I use a community action script (bcomnes/deploy-to-neocities) to do the actual uploads.
Here are some important things I've learned using deploy-to-neocities:
To work around these issues:
Here is my action script in full:
name: Deploy to neocities
# only run on changes to master
on:
workflow_dispatch:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: create output directories
run: mkdir publish publish/js publish/css
- name: copy files
run: cp -R *.html fonts images publish
- name: copy javascript
run: cp -R js/*.js publish/js
- name: copy css
run: cp -R css/*.css publish/css
# When the dist_dir is ready, deploy it to neocities
- name: Deploy to neocities
uses: bcomnes/deploy-to-neocities@v1
with:
api_token: ${{ secrets.NEOCITIES_API_TOKEN }}
cleanup: false
dist_dir: publish