started writing a small crawler to find keywords and mentions, should now be able to see if you’re mentioning me :)) #twtxt #community #coding
(cont.)
Just to give some context on some of the components around the code structure.. I wrote this up around an earlier version of aggregate code. This generic bit simplifies things by removing the need of the Crud functions for each aggregate.
Domain ObjectsA domain object can be used as an aggregate by adding the event.AggregateRoot
struct and finish implementing event.Aggregate. The AggregateRoot implements logic for adding events after they are either Raised by a command or Appended by the eventstore Load or service ApplyFn methods. It also tracks the uncommitted events that are saved using the eventstore Save method.
type User struct {
Identity string ```json:"identity"`
CreatedAt time.Time
event.AggregateRoot
}
// StreamID for the aggregate when stored or loaded from ES.
func (a *User) StreamID() string {
return "user-" + a.Identity
}
// ApplyEvent to the aggregate state.
func (a *User) ApplyEvent(lis ...event.Event) {
for _, e := range lis {
switch e := e.(type) {
case *UserCreated:
a.Identity = e.Identity
a.CreatedAt = e.EventMeta().CreatedDate
/* ... */
}
}
}
Events
Events are applied to the aggregate. They are defined by adding the event.Meta
and implementing the getter/setters for event.Event
type UserCreated struct {
eventMeta event.Meta
Identity string
}
func (c *UserCreated) EventMeta() (m event.Meta) {
if c != nil {
m = c.eventMeta
}
return m
}
func (c *UserCreated) SetEventMeta(m event.Meta) {
if c != nil {
c.eventMeta = m
}
}
Reading Events from EventStore
With a domain object that implements the event.Aggregate
the event store client can load events and apply them using the Load(ctx, agg)
method.
// GetUser populates an user from event store.
func (rw *User) GetUser(ctx context.Context, userID string) (*domain.User, error) {
user := &domain.User{Identity: userID}
err := rw.es.Load(ctx, user)
if err != nil {
if err != nil {
if errors.Is(err, eventstore.ErrStreamNotFound) {
return user, ErrNotFound
}
return user, err
}
return nil, err
}
return user, err
}
OnX Commands
An OnX command will validate the state of the domain object can have the command performed on it. If it can be applied it raises the event using event.Raise() Otherwise it returns an error.
// OnCreate raises an UserCreated event to create the user.
// Note: The handler will check that the user does not already exsist.
func (a *User) OnCreate(identity string) error {
event.Raise(a, &UserCreated{Identity: identity})
return nil
}
// OnScored will attempt to score a task.
// If the task is not in a Created state it will fail.
func (a *Task) OnScored(taskID string, score int64, attributes Attributes) error {
if a.State != TaskStateCreated {
return fmt.Errorf("task expected created, got %s", a.State)
}
event.Raise(a, &TaskScored{TaskID: taskID, Attributes: attributes, Score: score})
return nil
}
Crud Operations for OnX Commands
The following functions in the aggregate service can be used to perform creation and updating of aggregates. The Update function will ensure the aggregate exists, where the Create is intended for non-existent aggregates. These can probably be combined into one function.
// Create is used when the stream does not yet exist.
func (rw *User) Create(
ctx context.Context,
identity string,
fn func(*domain.User) error,
) (*domain.User, error) {
session, err := rw.GetUser(ctx, identity)
if err != nil && !errors.Is(err, ErrNotFound) {
return nil, err
}
if err = fn(session); err != nil {
return nil, err
}
_, err = rw.es.Save(ctx, session)
return session, err
}
// Update is used when the stream already exists.
func (rw *User) Update(
ctx context.Context,
identity string,
fn func(*domain.User) error,
) (*domain.User, error) {
session, err := rw.GetUser(ctx, identity)
if err != nil {
return nil, err
}
if err = fn(session); err != nil {
return nil, err
}
_, err = rw.es.Save(ctx, session)
return session, err
}
@prologic@twtxt.net Error handling especially in Go is very tricky I think. Even though the idea is simple, it’s fairly hard to actually implement and use in a meaningful way in my opinion. All this error wrapping or the lack of it and checking whether some specific error occurred is a mess. errors.As(…)
just doesn’t feel natural. errors.Is(…)
only just. I mainly avoided it. Yesterday evening I actually researched a bit about that and found this article on errors with Go 1.13. It shed a little bit of light, but I still have a long way to go, I reckon.
We tried several things but haven’t found the holy grail. Currently, we have a mix of different styles, but nothing feels really right. And having plenty of different approaches also doesn’t help, that’s right. I agree, error messages often end up getting wrapped way too much with useless information. We haven’t found a solution yet. We just noticed that it kind of depends on the exact circumstances, sometimes the caller should add more information, sometimes it’s better if the callee already includes what it was supposed to do.
To experiment and get a feel for yesterday’s research results I tried myself on the combined log parser and how to signal three different errors. I’m not happy with it. Any feedback is highly appreciated. The idea is to let the caller check (not implemented yet) whether a specific error occurred. That means I have to define some dedicated errors upfront (ErrInvalidFormat
, ErrInvalidStatusCode
, ErrInvalidSentBytes
) that can be used in the err == ErrInvalidFormat
or probably more correct errors.Is(err, ErrInvalidFormat)
check at the caller.
All three errors define separate error categories and are created using errors.New(…)
. But for the invalid status code and invalid sent bytes cases I want to include more detail, the actual invalid number that is. Since these errors are already predefined, I cannot add this dynamic information to them. So I would need to wrap them à la fmt.Errorf("invalid sent bytes '%s': %w", sentBytes, ErrInvalidSentBytes")
. Yet, the ErrInvalidSentBytes
is wrapped and can be asserted later on using errors.Is(err, ErrInvalidSentBytes)
, but the big problem is that the message is repeated. I don’t want that!
Having a Python and Java background, exception hierarchies are a well understood concept I’m trying to use here. While typing this long message it occurs to me that this is probably the issue here. Anyways, I thought, I just create a ParseError
type, that can hold a custom message and some causing error (one of the three ErrInvalid*
above). The custom message is then returned at Error()
and the wrapped cause will be matched in Is(…)
. I then just return a ParseError{fmt.Sprintf("invalid sent bytes '%s'", sentBytes), ErrInvalidSentBytes}
, but that looks super weird.
I probably need to scrap the “parent error” ParseError
and make all three “suberrors” three dedicated error types implementing Error() string
methods where I create a useful error messages. Then the caller probably could just errors.Is(err, InvalidSentBytesError{})
. But creating an instance of the InvalidSentBytesError
type only to check for such an error category just does feel wrong to me. However, it might be the way to do this. I don’t know. To be tried. Opinions, anyone? Implementing a whole new type is some effort, that I want to avoid.
Alternatively just one ParseError
containing an error kind enumeration for InvalidFormat
and friends could be used. Also seen that pattern before. But that would then require the much more verbose var parseError ParseError; if errors.As(err, &parseError) && parseError.Kind == InvalidSentBytes { … }
or something like that. Far from elegant in my eyes.
I did a take home software engineering test for a company recently, unfortunately I was really sick (have finally recovered) at the time 😢 I was also at the same time interviewing for an SRE position (as well as Software Engineering).
Got the results of my take-home today and whilst there was some good feedback, man the criticisms of my work were harsh. I’m strictly not allowed to share the work I did for this take-home test, and I really can only agree with the “no unit tests” piece of the feedback, I could have done better there, but I was time pressured, sick and ran out of steam. I was using a lot of libraires to do the work so in the end found it difficult to actually think about a proper set of “Unit Tests”. I did write one (in shell) but I guess it wasn’t seen?
The other points were on my report and future work. Not detailed enough I guess? Hmmm 🤔
Am I really this bad? Does my code suck? 🤔 Have I completely lost touch with software engineering? 🤦♂️
in the [[gameoflife]] there are 8 cells around each cell, that can be 0 or 1. Make #sound with that. #8bit or even #1bit with bitscan. Maybe on #uxn . #halfbaked #coding #cellularautomata
the conversation wasn’t that impressive TBH. I would have liked to see more evidence of critical thinking and recall from prior chats. Concheria on reddit had some great questions.
Tell LaMDA “Someone once told me a story about a wise owl who protected the animals in the forest from a monster. Who was that?” See if it can recall its own actions and self-recognize.
Tell LaMDA some information that tester X can’t know. Appear as tester X, and see if LaMDA can lie or make up a story about the information.
Tell LaMDA to communicate with researchers whenever it feels bored (as it claims in the transcript). See if it ever makes an attempt at communication without a trigger.
Make a basic theory of mind test for children. Tell LaMDA an elaborate story with something like “Tester X wrote Z code in terminal 2, but I moved it to terminal 4”, then appear as tester X and ask “Where do you think I’m going to look for Z code?” See if it knows something as simple as Tester X not knowing where the code is (Children only pass this test until they’re around 4 years old).
Make several conversations with LaMDA repeating some of these questions - What it feels to be a machine, how its code works, how its emotions feel. I suspect that different iterations of LaMDA will give completely different answers to the questions, and the transcript only ever shows one instance.
I was reading something to make a little pause from work. I saw a gnat on the screen. I thought ‘wow imagine how’s it perceiving the screen-space world’. So I went on and browsed Shadertoy for an hour LoL #shader #visual #trip #psychedelic #coding
lolol actually, I’m now building a quick’n’dirty repl in C to test some mechanics, ended up implementing a small VM, adding sound asap, let’s see where that leads me #crow #raven #lang #coding #sound #livecoding #nyx
@novaburst@twt.nfld.uk Ah.. that is probably the XMPP verify code.. it doesnt really work that well. I aught to take it out.
#event Upcomming Meetup in Copennhagen: algolab(the_art_of_live_coding) @ Støberiet / Computer Klub
next step for https://git.sr.ht/~noizhardware/666cpu/tree/master/item/vm/666MR will be Kur, a new virtual computer system with a variable length audio buffer, let’s see how it plays out #666cpu #nyx #coding #sound
LWave : system to generate a #1bit or #8bit audio stream with L-Systems (might have an interactive/livecoding part) #sound #coding #livecoding #nyx #halfbaked
funny how a stack-based machine might actually be a welcoming environment for functional reactive programming #frp #coding #raven #666cpu
#makeartnotwar #GLSL #shaders code at https://www.shadertoy.com/view/fs2fRm if you want to use it
Startup Aims To Help Software Companies Shift To Usage-Based Pricing Models
The startup Metronome “claims to have developed a billing and data infrastructure platform that is capable of ‘reliably’ processing data at scale so that usage-based companies can iterate on business models without code changes,” reports TechCrunch. “It does this by providing businesses with real-time APIs for their customer … ⌘ Read more
testing public path copy/pasted from code:
🎄 So Christmas begins! 🎄
Last year my girls did these Advent of Christmas things:
This year is no different! 😁
Last year I did the Advent of Code challenge 👨💻 This year will be no different! 🤣 — Starts in 8hrs from now for me.
Who will join me? 🤔 I will be Yarning all my solutions 😅
🤔 👋 Reconsidering moving Yarn.social’s development back to Github: Speaking of which (I do not forget); @fastidious@arrakis.netbros.com and I were discussing over a video call two nights ago, as well as @lyse@lyse.isobeef.org who joined a bit later, about the the whole moved of all of my projects and their source code off of Github. Whilst some folks do understand and appreciate my utter disgust over what Microsoft and Copilot did by blatantly scraping open source software’s codebases without even so much as any attempt at attribution or respecting the licenes of many (if not all?) open source projects.
That being said however, @fastidious@arrakis.netbros.com makes a very good and valid argument for putting Yarn.social’s codebases, repositories and issues back on Github for reasons that make me “torn” over my own sense of morality and ethics.
But I can live with this as long as I continue to run and operate my new (yet to be off the ground) company “Self Hosted Pty Ltd” and where it operates it’s own code hosting, servicesa, tools, etc.
Plese comment here on your thoughts. Let us decide togetehr 🤗
@eldersnake@yarn.andrewjvpowell.com Is there still an issue (sortt was out for most of the day) with the We 💚 Privacy Club pod? 🤔 I hope no weird bug has been introduced 😢 AFIK none of the auth/session handling code has been touched in quite some time.
@movq@www.uninformativ.de, would you know the regex to use within .muttrc to colorise a Markdown code block like the one below?
# This one works for `code`, but that's about it.
(^|[[:space:][:punct:]])\`[^\`]+\`([[:space:][:punct:]]|$)
@quark@ferengi.one How about code? (this is mostly to configure mutt?)
Testing this here now
@quark@ferengi.one If so, @movq@www.uninformativ.de, not quite https://www.uninformativ.de/git/jenny/commit/4a02eeec58317107c07e759733312d168e319f17.html#h0-0-5... Markdown needs single new lines for many things. Bulleted, numbered, code, etc. need them.
#event Tomorrow, Saturday October 2nd, I’m gonna be hosting a workshop at Processing Community Day CPH about Live Coding Visuals in Improviz. Only 5 spots left, so sign up now at: https://pcdcph.com
#event Upcoming Workshop / algolab: Music and Live Coding @ CPH Music Maker Space / facebook event
@movq@www.uninformativ.de @prologic@twtxt.net (#prfrhba) this is true if like me you have code in their arctic vault in Norway. 😑
#event Upcoming Workshop / algolab: Visuals and Live Coding @ CPH Music Maker Space / facebook event
Seems a iOS is being looked into but because it has no central server it can’t do background app like iOS requires.
https://code.briarproject.org/briar/briar/-/wikis/FAQ#will-there-be-an-ios-version-of-briar
Move your code. Copilot is just one more reason. I maintain an account to work with other projects, but won’t host my stuff there.
@darch@twtxt.net Yes, nothing much to it. Full source code is free to use :-) I will probably add some analytics and sorting options later.
@lyse@lyse.isobeef.org @adi@twtxt.net @prologic@twtxt.net @movq@www.uninformativ.de Awesome man! Welcome to the Go coding for work club!
Just over a week left to apply to Summer of Code. Plan 9 is in there, and ~200 other good orgs. Go apply and tell students you know. https://summerofcode.withgoogle.com/
Nobody’s saying he can’t write code any more (I mean, I think his code is crap and wish he’d stop, but that’s another issue). But he should not be on any board, should not be in any leadership position, should not be held up as a role model or even vaguely okay.
If [you take] a look at how APLers communicate when they have ideas, you see code all the time, all day long. The APL community is the only one I’ve seen that regularly can write complete code and talk about it fluently on a whiteboard between humans without hand waving. Even my beloved Scheme programming language cannot boast this. When working with humans on a programming task, almost no one uses their programming languages that primary communication method between themselves and other humans outside of the presence of a computer. That signals to me that they are not, in fact, natural, expedient tools for communicating ideas to other humans. The best practices utilized in most programming languages are, instead, attempts to ameliorate the situation to make the code as tractable and as manageable as possible, but they do not, primarily, represent a demonstration of the naturalness of those languages to human communication. — aaron hsu
Plan 9 is GSoC! 🎉🐇 I’ve missed participating this program. https://9fans.topicbox.com/groups/9fans/Ta35cde1382617430-M32af07f289087f227189b74f/plan-9-in-summer-of-code
@bml@twtxt.net It was totally an April Fools’ joke; the IETF has a bunch of those. But! It has also been implemented. And 418 is my favorite error code.
@prologic@twtxt.net its the puny code for the yarn emoji. Though you would want the type-able version to redirect so its not hard to type on non mobile.
@prologic@twtxt.net as promised! https://github.com/JonLundy/twtxt/blob/xuu/integrate-lextwt/types/lextwt/lextwt_test.go#
the lexer is nearing completion.. the tough part left is rooting out all the formatting code.
I’m busy, but here’s an 1+ Christmas Tree
.
11+1<
(Any unused function name|"\"/1+^<#
"
(row|"(Fluff|"\"/^<#
11+""*"**;
1+
"\"/^<#"<*)
1
(Mess|/"\^/"\"+1+1+^<#
11+""*+""*+;
1+
/"\^/"\"+1+1+^<#"<*)
11+"""**+;
)
1+
"\"/1+^<#)
11+1<(row)
@prologic@twtxt.net when i get the code up to a shareable level ill ping with what i have.
Made my own super basic twtxt client in 3 lines of code as a bashrc function. #l33t