pondering about the difference between my use of the tags #idea and #halfbaked . halfbaked looks like something in a more advanced stage, merely lacking execution #meta
pondering about the difference between my use of the tags #idea and #halfbaked . halfbaked looks like something in a more advanced stage, merely lacking execution #meta
@abucci@anthony.buc.ci Its not better than a Cat5e. I have had two versions of the device. The old ones were only 200Mbps i didnāt have the MAC issue but its like using an old 10baseT. The newer model can support 1Gbps on each port for a total bandwidth of 2Gbps.. i typically would see 400-500Mbps from my Wifi6 router. I am not sure if it was some type of internal timeout or being confused by switching between different wifi access points and seeing the mac on different sides.
Right now I have my wifi connected directly with a cat6e this gets me just under my providers 1.3G downlink. the only thing faster is plugging in directly.
MoCA is a good option, they have 2.5G models in the same price range as the 1G Powerline models BUT, only if you have the coax in wall already.. which puts you in the same spot if you donāt. You are for sure going to have an outlet in every room of the house by code.
I maintain keys for my email addresses.. but like most in this thread i almost never receive encrypted emails.. other than the BTC exchange i use that sends automated mail encrypted.
In about four monthsā time, if the replacement doesnāt ship from IndieGoGo before then, I will have been using my current smartphone for five years.
I use IP over Alternating Current at home. The only issue is the bridges forget device MACs sometimes and I get weird states where I can ping a deviceA and the the internet from deviceB. But deviceA can only ping device B even though they are on the same subnet and default gateway.
Does anyone of you use PGP encrypted mail, or any kind or email encryption? Why? Why not?
@prologic@twtxt.net I think we could use deltachats new decentralising app format for it: https://delta.chat/en/2022-06-14-webxdcintro
š Hello @burglar@txt.sour.is, welcome to txt.sour.is, a Yarn.social Pod! To get started you may want to check out the podās Discover feed to find users to follow and interact with. To follow new users, use the ⨠Follow button on their profile page or use the Follow form and enter a Twtxt URL. You may also find other feeds of interest via Feeds. Welcome! š¤
(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
}
Progress! so i have moved into working on aggregates. Which are a grouping of events that replayed on an object set the current state of the object. I came up with this little bit of generic wonder.
type PA[T any] interface {
event.Aggregate
*T
}
// Create uses fn to create a new aggregate and store in db.
func Create[A any, T PA[A]](ctx context.Context, es *EventStore, streamID string, fn func(context.Context, T) error) (agg T, err error) {
ctx, span := logz.Span(ctx)
defer span.End()
agg = new(A)
agg.SetStreamID(streamID)
if err = es.Load(ctx, agg); err != nil {
return
}
if err = event.NotExists(agg); err != nil {
return
}
if err = fn(ctx, agg); err != nil {
return
}
var i uint64
if i, err = es.Save(ctx, agg); err != nil {
return
}
span.AddEvent(fmt.Sprint("wrote events = ", i))
return
}
This lets me do something like this:
a, err := es.Create(ctx, r.es, streamID, func(ctx context.Context, agg *domain.SaltyUser) error {
return agg.OnUserRegister(nick, key)
})
I can tell the function the type being modified and returned using the function argument that is passed in. pretty cray cray.
by which the future life expectancy of some non-perishable things, like a technology or an idea, is proportional to their current age. Thus, the Lindy effect proposes the longer a period something has survived to exist or be used in the present, the longer its remaining life expectancy. The disproportionate influence of early tech decisions ā brandur.org
With respect to logging.. oh man.. it really depends on the environment you are working in.. development? log everything! and use a jeager open trace for the super gnarly places. So you can see whats going on while building. But, for production? metrics are king. I donāt want to sift through thousands of lines but have a measure that can tell me the health of the service.
@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 have updated my eventDB to have subscriptions! It now has websockets like msgbus. I have also added a in memory store that can be used along side the disk backed wal.
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? š¤¦āāļø
Hi, I am playing with making an event sourcing database. Its super alpha but I thought I would share since others are talking about databases and such.
Itās super basic. Using tidwall/wal as the disk backing. The first use case I am playing with is an implementation of msgbus. I can post events to it and read them back in reverse order.

I plan to expand it to handle other event sourcing type things like aggregates and projections.
Find it here: sour-is/ev
@prologic@twtxt.net @movq@www.uninformativ.de @lyse@lyse.isobeef.org
In typography, an asterism, ā, is a typographic symbol consisting of three asterisks placed in a triangle, which is used for a variety of purposes. Asterism (typography) - Wikipedia)
Iām trying to switch from Konversation to irssi. Letās see how that goes. Any irssiers out there who can recommend specific settings or scripts? I already got myself trackbar.pl and nickcolor.pl as super-essentials. Also trying window_switcher.pl. Somehow my custom binds for Ctrl+1/2/3/etc. to switch to window 1/2/3/etc. doesnāt do anything: { key = "^1"; id = "change_window"; data = "1"; } (I cannot use the default with Alt as this is handled by my window manager). Currently, Iām just cycling with Ctrl+N/P. Other things to solve in the near future:
- better, more colorful and compact theme (just removed clock from statusbar so far)
- getting bell/urgency hints working on arriving messages
- nicer tabs in status bar, maybe even just channel names and no indexes
- decluster status bar with user and channel modes (I never cared about those in the last decade)
ā¤ļø š¶: Two of Us by ALi
I will probably crash in the afternoon but right now I am going to use my energy to take a walk outside
All the scripts on my Gemini capsule (except chess) have now been rewritten using Python and storing data in a SQLite database. This is the first time Iāve ever worked with database in a āproductionā environment, and Iām inordinately excited.
Hmm, @prologic@twtxt.net / @lyse@lyse.isobeef.org: Should we remove the section āTraditional Human-Readable Topicsā from the spec? Or mark is as deprecated? I havenāt seen this being used in the wild for years. š¤
@chronolink@chrono.tilde.cafe Replies are not part of the original twtxt format. They were added later as an extension by Yarn.social: https://dev.twtxt.net/doc/twtsubjectextension.html (only the section āMachine-Parsable Conversation Groupingā is used these days)
@prologic@twtxt.net Oh.. reading comprehension is strong today.. you went to US and now back.
We moved to the US. When we got back we just never got new chickens again š¢
@movq@www.uninformativ.de I usually only use eggs for baking or fry them for potatoes and spinach. @prologic@twtxt.net Why donāt you have them anymore? Did the fox get them all when the door didnāt close in time? ]:->
ā¤ļø š¶: What about us by Hajin
started using an email address with my own domain name
All this time spent being grumpy about how adding my Now updates directly into the html page is uncomfortable, and it just occurred to me I can chug it into a text file and use cat.
Types of Scopes
ā Read more
Field Topology
ā Read more
We donāt have meaningful social connections anymore like our parents or their parents geeration had. We are so scattered, that I am unsure how many of my friends are actually friends and how many are just professional contacts. Everytime I switch job, almost 70% of my friends suddenly fall out of contact. Heck, I donāt even know the people who live in next apartments both left, right, up and down on the same building. Socializing with my friends mean, setting up an appointment weeks ahead to see if we can align on a free-slot and this often involves all of us commuting to somewhere and disbanding by 22:00 hours because family, work next morning, chores to do, doctor appointment and other human things. Why do you waste so much time on the internet? | Hacker News
Health Data
ā Read more
I donāt use social media anymore, mostly for privacy reasons, but one of the things I miss about it is being able to interact directly with creators I enjoy.
Iāve noticed a gradient of skepticism about climate change, ranging from outright contradiction that it exists to debates about the specific measures needed to reverse acknowledged warming trends. Using the general term āclimate change denialā to describe that entire gradient, and thus treating all forms of skepticism as equally ignorant, seems counterproductive to me.
English is probably the worst language you could use to translate any Asian language into Lost in Translation: Drama Titles That Steer You in the Wrong Direction - MyDramaList
Among a multitude of stars, one stares down at me. Among a multitude of people, I stare up at that one star. As the night grows deeper, it fades into brightness and I disappearĀ into darkness. Where, when, as what will the two of us⦠you, one so warm, and me, one so tender, meet again? Encounter ā My Kdrama Addiction
ā¤ļø š¶: Itās Cold (Take Care Of Us Captain OST) by Song Ji Eun
@mutefall@twtxt.net interesting.. were you working on one of the two universities that used it between 1989 and 1991?
started using esglua, our static site generator | https://compudanzas.net/esglua.html
#live #music idea: revived devices used as instruments, #sound coming from their own speakers. #livecoding #permacomputing #666cpu #uxn
#live #music idea: revived devices used as instruments, #sound coming from their own speakers. #livecoding #permacomputing #666cpu #uxn
Salary Negotiation
ā Read more
idea: using a #matrixmixer to generate feedback exciting membranes with a piezo. Try an irish drum #minijack #video #sound
idea: using a #matrixmixer to generate feedback exciting membranes with a piezo. Try an irish drum #minijack #video #sound
@prologic@twtxt.net yeah. For commercial use even. Just need to put an attribution note in the project README
@xuu@txt.sour.is So that means weāre allowed to use it right? š
@lyse@lyse.isobeef.org Excellent use of old denim, and also excellent use of long-form twt!