Monday, March 21, 2022
Zig open interfaces issues
Friday, February 25, 2022
SBE Repeating Group Gotchas
- There is very little documentation in general, and for repeating groups it's incomplete. A big omission: you must always explicitly decode every member of every repeating group, in the same order as they are defined in your schema. If you do not do this, your results could be mysteriously corrupted. Alternatively, you could explicitly "skip" the ones you are not interested in, with the relatively new sbeSkip() call. E.g.
weWantSerialNumber(carDecoder.serialNumber());
weWantModelYear(carDecoder.modelYear());
FuelFiguresDecoder fuelFigures = fuelFigures(); //we don't want fuelfiguresif (fuelFigures.count() > 0) //but if it was encoded...
{ //we must iterate over it anyway
while (fuelFigures.hasNext())
{
fuelFigures.next();
fuelFigures.sbeSkip();
}
}
PerformanceFiguresDecoder performanceFigures = performanceFigures();
if (performanceFigures.count() > 0)
{
while (performanceFigures.hasNext())
{
performanceFigures.next();
weWantOctaneRating(performanceFigures.octaneRating());
performanceFigures.sbeSkip(); //actually needed in the sample} //because there's a nested repeating group!
}
- If you're working with code that does not use repeating groups, and you add one, lots of things might break unexpectedly. Because wrapping a decoder with an incorrect blockLength will mostly work if you don't need to decode repeating groups or variable length data fields. You need to use the blockLength on a header message, which in turn needs to be the BLOCK_LENGTH of the encoder. This excludes the length of the repeating groups. On the bright side, nowadays there are wrapAndApplyHeader() convenience methods on both the encoder and decoder objects.
- If you want to read repeating groups from the same decoder more than once, you need to call sbeRewind().
- There's currently a bug in which toString can break repeating groups
Thursday, February 17, 2022
Bookmarks and Full Text Search
They suck because they don't actually work for their primary use cases:
1. where did I read about that cool thing X?
2. where was that cool article about Y that I didn't have to time to read, but would like to read now?
Heck, at some point I found it easier to google for pages instead of trying to find them in my bookmarks.
Other use cases should be handled slightly differently:3. "Bookmarks Bar", "Pin a tab", and "Save a shortcut" features are all useful for commonly-used pages or web apps.
4. "Manage Search Engines" feature is useful for sites that you want to search often.
4. I'll bet Chrome soon adds support for saving tab groups, which will be useful for gathering lots of pages for a particular project, e.g. a bibliography.
Practically speaking, labels and categorization are annoying to add, and don't really help find things later. The titles that maintainers give to web pages are also often unhelpful for retrieval.
The solution is automatic full text search of all bookmarked pages.
Worldbrain's Memex supports full text search of bookmarks well, and for free. I have mixed feelings about it. On the one hand, this feature is implemented by an open source plugin, and the maintainers support local first software. On the other hand, they have a much bigger vision, and it's unclear how much they want to support the free part of it. It currently sports a non-dismissible reddish prompt to register for the cloud support.
Friday, January 28, 2022
iPhone Shul Shush
Now it's finally possible to silence iPhones in shul (or church or whatever)!
- Settings / Focus / Do Not Disturb / Add Schedule or Automation / Location
- enter something to identify your shul, e.g. part of the name
- select the right one
- touch Done
Monday, January 03, 2022
Vim plugin idea
When working with verbose logs, you want to suppress uninteresting lines.
So, wouldn't it be cool if you could select two lines, and vim would hide all lines that are similar to them.
1237 boring is blah, all good
1238 boring is foo, all good
1238 WARNING
1240 boring is blah, again
When the user selects the first two lines above, vim would hide lines matching the pattern \d+ boring is \w+, all good.
It'd need the ability to unhide the next or previous line.
We could also get fancy, and support generalizing previous patterns. In the example above, you could later choose the fourth line, and vim would amend the previous pattern to \d+ boring is \w+, [ a-z]*. We'd have to document some decisions about how general to be, e.g. it's not obvious above that we should use \d+ instead of 123\d.
Closest existing thing I could find: https://www.vim.org/scripts/script.php?script_id=2302
Thursday, December 30, 2021
Scrolling two files curmudgeonry
It's useful to be able to synchronize scrolling through two files, especially for comparing two files that have too many intraline differences.
Vim supports this, with this annoying incantation:
vim -O oneFile anotherFile -c "windo set scrollbind" -c "windo set scrollopt+=hor" -c "windo set nowrap" -c "windo set cursorbind"
Switch between the windows with: ctrl-w ctrl-w
Nowrap is useful because otherwise different sized lines don't display nicely.
Other annoying things:
- The documentation can't decide what this feature is called, scroll binding or scrolling synchronously.
- Gvim doesn't seem to support cursorbind.
Tuesday, October 19, 2021
Toki Pona
Toki Pona is a supremely simple constructed language. It's a real Newspeak (from Orwell's 1984), but for good and not evil.
It's very cool. Unfortunately nobody seems to seriously use it for international collaboration. (Apparently this is called auxlang, and obviously English right now is it.)
I was initially grumpy about the "pre-verb" part of speech, but now I believe it's consistent with the general rule that a word modifies its preceding word. For example, a noun precedes its adjectives, and a verb precedes its adverb. So: mi ken pali == I can work. mi wile e ken pali == I want the ability to work.
Wednesday, July 21, 2021
Nullaway @Initializer
Nullaway is the currently most practical solution to the billion dollar mistake.
Its @Initializer annotation is one of its practical features; if an object is not expected to be used until one of its methods in executed, that method can be annotated. Then fields can still be statically guaranteed to be non-null if they are initialized in that method, even if they are not initialized earlier.
Nullaway does not, however, statically guarantee that @Initializer methods are actually executed. Therefore, it's better to initialize non-nullable fields in a constructor.
Friday, June 04, 2021
Poor Man's Projectional Editing
Projectional Editing is programming that goes beyond simple text entry. Notable projects are Lamdu and Jetbrain's MPS and to some extent Intellij itself.
Historically, programmers have been reluctant to stray too far from textual programming. A good compromise approach is to represent language features both textually and graphically. For example, the exponents in LegibleMathematics are both superscripted and ^ prefixed.
We could support the property of always keeping the program valid, and still give the feel of textual editing:
- as the user types, insert code to make the program valid
e.g. if the user types if, then we'll insert (true) {} - in the inserted code, automatically select the next bit that isn't forced, to clarify that it will be replaced as the user types
e.g. in the case of inserted (true) {}, we'll select the (true) - in general, whenever the user types the same thing as the next required bit, just advance the insertion point over it
e.g. in some existing code if (x) { y(); } the user clicks before the semicolon and types ; }, we won't change anything at all, and just advance the insertion point to after the }
If we want to support whitespace, then we could change the traversed text to use the new whitespace that the user types.
void f() {
if (foo) {bar();baz();}
qux();
quux();}
void f() {if (foo) {bar();g();}qux();quux();}void g() {baz();}
And of course select the new function name g so that it can be easily changed. And some pastes would be illegal, e.g. pasting qux(); quux() in place of foo.
So, this "always valid" approach is very nice for refactoring. Its main benefit however is to enable powerful live coding, e.g. devcards.
Git gotcha
Since the rise of github, most teams build software using a pull request workflow. Therefore the local "master" branch is a bit of a gotcha. You can commit to it, but that will only ever cause you grief. That is, you'll forget about those commits, and they'll eventually cause a conflict, and you'll get something mysteriously broken when you just want "master". Fix it with this:
git branch -D master
git branch master origin/master
And actually consider not having a local master at all, and always using origin/master instead.
Wednesday, March 03, 2021
Watches making sure you're "up"
Wednesday, September 23, 2020
IPython replacing shell
IPython is a good UNIX shell replacement, for those who want an interactive shell with a better programming language.
You can use unadorned shell commands, file globbing, and pipes, as well as regular python.
Regular shell: ls *.py | grep -v foo
Regular python: for x in range(3): print(x)
There is special syntax for running shell commands to be easily used by python code...
Shell in python: my_python_var1 = !ls #only for assigning variables
Python in shell: ls $my_python_var2
For anybody pining for python2: print "foo" #works!
Also works for any outermost python function: dir enumerate(list())
But unfortunately doesn't currently work with other code: for x in range(3):
print x
For some reason, the maintainers are no longer publishing a profile for this stuff, so you can use the following to get up and running:
pip install ipython
cat >> ~/.ipython/profile_default/ipython_config.py <<EOF
from IPython.terminal.prompts import Prompts, Token
import os
class MyPrompt(Prompts):
def cwd(self):
cwd = os.getcwd()
if cwd.startswith(os.environ['HOME']):
cwd = cwd.replace(os.environ['HOME'], '~')
cwd_list = cwd.split('/')
for i,v in enumerate(cwd_list):
if i not in (1,len(cwd_list)-1): #not last and first after ~
cwd_list[i] = cwd_list[i][0] #abbreviate
cwd = '/'.join(cwd_list)
return cwd
def in_prompt_tokens(self, cli=None):
return [
(Token.Prompt, 'In ['),
(Token.PromptNum, str(self.shell.execution_count)),
(Token.Prompt, '] '),
(Token, self.cwd()),
(Token.Prompt, ': ')]
c.TerminalInteractiveShell.prompts_class = MyPrompt
c.TerminalInteractiveShell.editing_mode = 'vi'
c.InteractiveShell.autocall = 2 #insert parens around functions as much as possible
c.InteractiveShellApp.exec_lines = ['%rehashx']
Wednesday, May 27, 2020
Select and Lookup
Select
Lookup
Monday, February 24, 2020
Automated tests and new bugs
Russ Cox offhandedly mentions that, no, unit tests only "make sure bugs you fix are not reintroduced over time", in his brilliant recent piece on versioning in go.
On the other hand, Hillel Wayne has a nice example using property based testing and contracts. See if you can spot the bug yourself before following that link:
def mode(l):
max = None
count = {}
for x in l:
if x not in count:
count[x] = 0
count[x] += 1
if not max or count[x] > count[max]:
max = x
return max
Hillel analyzes several different approaches to testing. The punch line is that you catch the bug with the following steps:
- annotate the mode function with its specification:
@ensure("result must occur at least as frequently as any member", lambda a, r: all((a.l.count(r) >= a.l.count(x) for x in a.l))) - also prepend the following:
from hypothesis import given from hypothesis.strategies import lists, integers, text from dpcontracts import require, ensure @given(lists(text())) def test_mode(l): mode(l) - install the prerequisites with:
pip3 install hypothesis dpcontracts pytest - run pytest on the file that you created with the mode function and its test code
In contrast, a specification can be easier to read than any practical implementation. At least with current technology, there are limits on how clear pragmatic code can be. Specification-like code can be too slow. Perhaps the specification could be an oversimplified implementation, and still be useful for testing.
Testing based purely on the specification is not enough however. We need some automated equivalent of "clear box testing".
Thursday, January 16, 2020
Zig
Zig's main advantage over C is robustness. That includes features like:
- better error handling
- optional instead of null pointers
- undefined behavior handling, either at compile time or configurably
- no magic
- seamless interoperability
- similar reach, via LLVM
Tuesday, January 07, 2020
Beyond Literate Programming
Programs must be written for people to read, and only incidentally for machines to execute.― Harold Abelson
More important to read a program than to run it? Absurd! How can something even be a called a program if it can't be executed by a machine? So soften the hyperbole: programs should first be written to be easy to read, and only afterwards optimized. It's the opposite of premature optimization.
The quote's hyperbole is good, because technical debt is caused by customers benefiting only directly from machines executing programs, as opposed to anything associated with people reading programs' source code. All maintenance programming starts with people reading. So this could be a programming principle that's more important than extensibility, discoverability, clean code, clean architecture, SOLID, DRY, YAGNI, KISS, least astonishment, defensive programming, offensive programming, cohesion&coherence, consistent style, information hiding, and good separation of concerns. Let's call it the readability principle: programs should be written in such a way as to communicate their function as clearly as possible. "Function" refers to function which is meaningful to the user. "Communicate" refers to informing somebody who is not already familiar with the program, and not even an expert in all of the technologies employed. This implies that programmers should avoid both Rube Goldberg machines and fancy language features.
Knuth's literate programming is the original push to have a single program provide both function and documentation. Its most popular descendant is the Javadoc family, which is now the standard way to document APIs. Jupyter Notebooks and Devcards publish executable documentation. Concordion brings together test code and documentation in a lovely way. All of these involve additional program documentation, which is not itself executable. Of course this should not distract from making properly self-documenting code. All additional documentation must have clear and agreed benefit, to justify the cost of manually keeping it up-to-date with the program itself.
The next big thing in program readability is humble: put design documents and technical specifications in the same repository as your program! And favor the markdown format. The best new source control repositories (Github, Bitbucket, and Gitlab) all render it automatically to the web. Having program and doc together makes it easier to keep them in the sync. Versions and links are easier, as well as running find-and-replace across program and doc. Perhaps most importantly, if you keep program and documentation together, you signal that programmers should maintain both.
Simplicity
Thursday, March 28, 2019
Translating objects simply
- Use a single function with a single line for each field on the object to which you are translating.
- Whenever you need something new, do the simplest thing that could possibly work.
- There is no step 3!
foo.setC(bar.getQux());
foo.setB(bar.getB()+1);
foo.setD(d.getSomePart());
foo.setE(d.getSomeOtherPart());
foo.setNestedF(fBarTranslator.translate(bar));
if (bar.getFloat() != null) foo.setPrimitiveFloat(bar.getFloat());
Organizing the code in terms of the target object achieves some "functional programming" goodness. Stakeholders often ask questions like "why does this field have this value? where does it come from?" and our code makes it easy to answer that kind of question. Each of the lines in the translation function is like a definition of the target object field. Though a single field on the source object might contribute to the value of multiple fields on the target object, a single field on the target object is only ever determined by a single complete function.
For fields with nontrivial logic, that logic should reside in a function in a different class, a la Single Responsibility Pattern. (I favor static methods for pure logic and field injection for logic that needs to consult some state, but there are good reasons to do otherwise.)
Any additional architecture only ever harms your code! Resist the temptation to add architecture. It will not pay for itself.
An important rule that you can't see in the examples above: never retrieve information from the target while you are translating to it. Another thing that might not be obvious: if your translation is a nice normal stateless translation, then your translator class should not have any member variables. Use local variables and not member variables for your expensive calculations.
If you have more than a handful of fields, you might want to order your setter calls alphabetically. That makes it harder for developers to accidentally set the same field twice in the same function. It makes it easy to find a field on a printout or to consult multiple fields without having to search via the app. It also makes git merge conflicts smarter; you want a conflict when two different developers merge different code for setting the same field, but you don't want a conflict when two different developers merge code for setting two different new fields. Just adding support for new fields to the end of the function yields a conflict in both cases.
Adding support for new fields to the end of the function is not a guideline which is easy to defend, or which is even easy for faithful developers to see in the code. If that's your de facto organizing principle, then you'll end up with no organizing principle. In contrast, if you alphabetize and have clear standards around dependency injection etc as mentioned above, you'll have one canonical simplest possible program for any translation. One right way to do it.
Friday, December 28, 2018
The Web is a detail?
Yes, if you can do it right.
If you do it wrong, you'll end up with a big hunk of useless complexity. You have been warned. The rest of this post describes one way of "doing it right" in Java. TL;DR use Autovalue and Mapstruct in a separate module.
One of the nicest things about Java is that it allows checking your interfaces at compile time, before running any of your code. So you can have one module that depends on the interfaces of your transport technology, and another module that doesn't. You can even have Maven prevent people from accidentally spreading that dependency.
This enables building and testing the domain code entirely independently of transport technology choice. Ideally, you could add support for another transport later by adding another module and not making any changes to your domain code. If your transport technology involves code generation, you might keep the generated Data Transfer Objects (DTOs) in the same module as your adapter code.
If you need multiple transports from day one, then this architecture is obviously the right way to go. It's more controversial if you're starting with a single transport, and it's also easier to get wrong. There's a strong argument to be made that you aren't going to need it. Besides being disciplined about dependencies, the most important thing is to keep the adapter layer small. We can do that with some open source code generation tools...
Let's say that you have a bunch of DTOs to work with messages that are sent and received by your message encoding technology, e.g. Google Protocol Buffers (Protobuf). Instead of working with those technology specific objects directly, your domain code can work with corresponding lightweight value objects.
Initially, you'll want to have one abstract class corresponding to each Protobuf message. With a little bit of annotation, AutoValue will nicely generate value objects for you, as well as fluent builders to compensate for Java's lack of named parameters. Here's an example, assuming you have a FooRequest message with fields bar and baz:
@AutoValue
abstract class FooRequest {
abstract int getBar();
abstract String getBaz();
Builder builder() { return new AutoValue_FooRequest.Builder(); }
@AutoValue.Builder
static abstract class Builder {
abstract Builder setBar(int i);
abstract Builder setBaz(String s);
abstract FooRequest build();
}
}
That goes in your domain module, and your domain code can proudly rely on it. Imagine a similar FooResponse. For example, you might have a FooUseCase with a method that accepts a FooRequest. E.g.
@Singleton
class FooUseCase {
FooResponse handle(FooRequest r) {
someFunction(r.getFoo(), r.getBar());
return FooResponse.builder()
.setBar(...)
.setBaz(...)
.build();
}
...
}
To map between the DTO and the domain object, use the following Mapstruct annotated abstract class in the adapter module:
@Singleton
abstract class FooUseCaseAdapter {
FooRequestMapper requestMapper = new FooUseCaseAdapter$FooRequestMapperImpl(); //generated by mapstruct
FooResponseMapper responseMapper = new FooUseCaseAdapter$FooResponseMapperImpl(); //generated by mapstruct
@Inject FooUseCase foo;
@Inject Sender sender;
void handle(FooIncomingMessage m) {
sender.send(responseMapper.map(foo.handle(requestMapper.map(m)));
}
@Mapper(unmappedTargetPolicy=ERROR, unmappedSourcePolicy=IGNORE)
static abstract class FooRequestMapper {
FooRequest map(FooIncomingMessage m);
}
@Mapper(unmappedTargetPolicy=IGNORE, unmappedSourcePolicy=ERROR)
static abstract class FooResponseMapper {
FooOutgoingMessage map(FooResponse r);
}
}
Using Mapstruct means that you don't have to write adapter code for each field. If you have a field of the same name in the DTO class and in the Autovalue class, the generated code will map that field automatically. The "unmapped" policy of ERROR means that you will be stopped at compile time from accidentally renaming a field in the DTO but not in the domain, or vice versa. It also prevents you from forgetting to add a field to the DTO when you add a field to the domain. You'll want to use the "target" and "source" as above, lest you get lots of false positives as people evolve the DTOs independently of your application.
So our YAGNI overhead is two trivial classes for each DTO. One of them needs two lines for each DTO field used by the application. Considering that the application needs changes anyway to use a new field, those two extra changes do not seem onerous. Besides not having to write and maintain the generated code, there's the advantage that its design doesn't drift. The Autovalue classes may accumulate logic, via interfaces and default values, for example. That's perfectly fine.
This whole exercise assumes that most of your automated tests will be on the Autovalue classes. The unmapped error policy reduces the risk of bugs, even if you don't test the DTO mapping at all, but the paranoid among us might want to have a test or two to exercise each field. Mapstruct is smart enough to map between different types, so that you can use an long integer on your DTO and an Instant in your domain, for example. If you use that feature, it makes sense to test it.
What about generated enum types? Perhaps compromise is best here: generate or pull the enum classes into a separate module, and as long as these don't do strange things in static initialization, just rely on that module in the domain. The opportunity for coupling related to enums should be small. The alternative is to duplicate all the enums manually. Though Mapstruct will automatically map and warn regarding those too, that overhead may not pay for itself, especially for enums that have values that the application just needs to pass on without special handling.
Notice in the example above that a single adapter handles publishing as well as incoming message processing. We could have the domain code return a tuple-like object which contains references to Autovalue objects for all of the messages which could be published in reaction to the incoming message. This is very easy to test, and doesn't require any mocking at all. Alternatively, we could instead have the domain call some kind of publisher interface, with two implementations: a mock implementation for testing, as well as an adapter of the real transport. The real implementation would be bound to the interfaces using a dependency injection configuration in the adapter. This approach enables the adapters to be quite uniform, and to hardly ever change. If the number of possible messages to publish for each case is small, the first approach is simpler.
Tuesday, February 20, 2018
State
This complexity is caused by our inability to properly manage "state", or information that changes over time. Procedural programming, object oriented programming, domain driven design, immutable data structures, and monads are all attempts to better manage state, and none of them are good enough.
The more recent functional reactive technologies are a step in the right direction. React is good, and MobX, Javelin, and Matrix are better. Serious programming can be as easy as spreadsheets. We can have full referential transparency, and we can refactor without fear.
