Posts in Kotlin (6 found)
Anton Zhiyanov 2 weeks ago

Go is #2 among newer languages

I checked out several programming languages rankings. If you only include newer languages (version 1.0 released after 2010), the top 6 are: ➀ TypeScript, ➁ Go, ➂ Rust, ➃ Kotlin, ➄ Dart, and ➅ Swift. Sources: IEEE , Stack Overflow , Languish . I'm not using TIOBE because their method has major flaws. TypeScript's position is very strong, of course (I guess no one likes JavaScript these days). And it's great to see that more and more developers are choosing Go for the backend. Also, Rust scores very close in all rankings except IEEE, so we'll see what happens in the coming years.

0 views
James O'Claire 4 months ago

The Trackers and SDKs in ChatGPT, Claude, Grok and Perplexity

Well for a quick weekend recap I’m going to look at which 3rd party SDKs and API calls I can find in the big 4 Android chat apps based. We’ll be using free data from AppGoblin which you can feel free to browse at any of the links below or on tables. Data is collected via de-compiled SDKs and MITM API traffic. Let’s look first at the development tools. These were interesting to me because I had assumed I’d see more of the dynamic JavaScript libraries like React. Instead we see these are all classic Kotlin apps. If you click through the Chat App names you’ll see the more detailed breakdowns of which specific parts of the libraries they’re using like e (in app animations library) or Kotlin Coil Compose or Square’s . Wow, way more than I expected and with quite the variety! I guess it’s enough we can further break these down. As is common now, most apps have more than one analytics tracker in their app. First up let’s recognize Google, it’s across every app in multiple ways. The main one that is used in most apps is the . GMS which is required for both Firebase and Google Play Services. Here’s an example of the measurement SDKs related to this: Next was statsig.com and wow! I was blown away I found this one in 3 of the 4 apps. This looks like a super popular company and I was surprised as I hadn’t heard of them before. Looking around, they look a bit more developer / product focused, but have tons of features and look quite popular. Finally in the analytics section we’ll add the classic segment.com (marketing analytics) and sentry.io (deployment analytics) which get to call OpenAI and Anthropic as it’s clients. It’s always interesting how every company from games to AI end up needed multiple analytics platforms and probably still depend most on their home BI/Backend. Here’s where the money is at. Now SUPER cool is that RevenueCat is now in both OpenAI and Perplexity. RevenueCat helps to use react native updatable web payment / subscription walls so that marketers can change those sections of the apps without needing to do an entire app update. I believe Perplexity is using Stripe, but that could also be a part of their bigger app ecosystem livekit.io ( AppGoblin livekit.io ) is an AI voice platform which is used by OpenAI and Grok. I’m surprised that OpenAI uses this, as they were quite early to the voice game, but perhaps they use this for some deeper custom voice tools. Perplexity has the most interesting third party tools with MapBox and Shopify. I believe MapBox, which delivers mapping tiles, is used for some of Perplexity’s image generation tools like adding circles/lines etc to maps. After seeing Shopify in Perplexity, I realized there wasn’t a Shopify SDK found for OpenAI (despite checking recently). They have been rolling out shopping features as a way to monetize their app, so I am curious if these are just implemented via API or if they were obfuscated well enough to not be found. If you’re still interested, you can also check out the API calls recorded by each app while open. The data is scrubbed, and I’m not sharing the clear text JSONs associated, but you can see some of the endpoints related to the SDKs. If you have further questions about these, or have a specific piece of data (say GPS, or email) that you’d like to check if it is sent along to any of these, just let me know and we can do further research: https://appgoblin.info/apps/com.openai.chatgpt/data-flows https://appgoblin.info/apps/com.anthropic.claude/data-flows If you have feedback please join the https://appgoblin.info Discord, you can find the link on the home page.

0 views
baby steps 7 months ago

Rust in 2025: Language interop and the extensible compiler

For many years, C has effectively been the “lingua franca” of the computing world. It’s pretty hard to combine code from two different programming languages in the same process–unless one of them is C. The same could theoretically be true for Rust, but in practice there are a number of obstacles that make that harder than it needs to be. Building out silky smooth language interop should be a core goal of helping Rust to target foundational applications . I think the right way to do this is not by extending rustc with knowledge of other programming languages but rather by building on Rust’s core premise of being an extensible language. By investing in building out an “extensible compiler” we can allow crate authors to create a plethora of ergonomic, efficient bridges between Rust and other languages. When it comes to interop… When it comes to extensibility… In my head, I divide language interop into two core use cases. The first is what I call Least Common Denominator (LCD), where people would like to write one piece of code and then use it in a wide variety of environments. This might mean authoring a core SDK that can be invoked from many languages but it also covers writing a codebase that can be used from both Kotlin (Android) and Swift (iOS) or having a single piece of code usable for everything from servers to embedded systems. It might also be creating WebAssembly components for use in browsers or on edge providers. What distinguishes the LCD use-case is two things. First, it is primarily unidirectional—calls mostly go from the other language to Rust. Second, you don’t have to handle all of Rust. You really want to expose an API that is “simple enough” that it can be expressed reasonably idiomatically from many other languages. Examples of libraries supporting this use case today are uniffi and diplomat . This problem is not new, it’s the same basic use case that WebAssembly components are targeting as well as old school things like COM and CORBA (in my view, though, each of those solutions is a bit too narrow for what we need). When you dig in, the requirements for LCD get a bit more complicated. You want to start with simple types, yes, but quickly get people asking for the ability to make the generated wrapper from a given language more idiomatic. And you want to focus on calls into Rust, but you also need to support callbacks. In fact, to really integrate with other systems, you need generic facilities for things like logs, metrics, and I/O that can be mapped in different ways. For example, in a mobile environment, you don’t necessarily want to use tokio to do an outgoing networking request. It is better to use the system libraries since they have special cases to account for the quirks of radio-based communication. To really crack the LCD problem, you also have to solve a few other problems too: Obviously, there’s enough here to keep us going for a long time. I think the place to start is building out something akin to the “serde” of language interop: the serde package itself just defines the core trait for serialization and a derive. All of the format-specific details are factored out into other crates defined by a variety of people. I’d like to see a universal set of conventions for defining the “generic API” that your Rust code follows and then a tool that extracts these conventions and hands them off to a backend to do the actual language specific work. It’s not essential, but I think this core dispatching tool should live in the rust-lang org. All the language-specific details, on the other hand, would live in crates.io as crates that can be created by anyone. The second use case is what I call the deep interop problem. For this use case, people want to be able to go deep in a particular language. Often this is because their Rust program needs to invoke APIs implemented in that other language, but it can also be that they want to stub out some part of that other program and replace it with Rust. One common example that requires deep interop is embedded developers looking to invoke gnarly C/C++ header files supplied by vendors. Deep interop also arises when you have an older codebase, such as the Rust for Linux project attempting to integrate Rust into their kernel or companies looking to integrate Rust into their existing codebases, most commonly C++ or Java. Some of the existing deep interop crates focus specifically on the use case of invoking APIs from the other language (e.g., bindgen and duchess ) but most wind up supporting bidirectional interaction (e.g., pyo3 , [npapi-rs][], and neon ). One interesting example is cxx , which supports bidirectional Rust-C++ interop, but does so in a rather opinionated way, encouraging you to make use of a subset of C++’s features that can be readily mapped (in this way, it’s a bit of a hybrid of LCD and deep interop). I want to see smooth interop with all languages, but C and C++ are particularly important. This is because they have historically been the language of choice for foundational applications, and hence there is a lot of code that we need to integrate with. Integration with C today in Rust is, in my view, “ok” – most of what you need is there, but it’s not as nicely integrated into the compiler or as accessible as it should be. Integration with C++ is a huge problem. I’m happy to see the Foundation’s Rust-C++ Interoperability Initiative as well a projects like Google’s crubit and of course the venerable cxx . The traditional way to enable seamless interop with another language is to “bake it in” i.e., Kotlin has very smooth support for invoking Java code and Swift/Zig can natively build C and C++. I would prefer for Rust to take a different path, one I call the extensible compiler . The idea is to enable interop via, effectively, supercharged procedural macros that can integrate with the compiler to supply type information, generate shims and glue code, and generally manage the details of making Rust “play nicely” with another language. In some sense, this is the same thing we do today. All the crates I mentioned above leverage procedural macros and custom derives to do their job. But procedural macrods today are the “simplest thing that could possibly work”: tokens in, tokens out. Considering how simplistic they are, they’ve gotten us remarkably, but they also have distinct limitations. Error messages generated by the compiler are not expressed in terms of the macro input but rather the Rust code that gets generated, which can be really confusing; macros are not able to access type information or communicate information between macro invocations; macros cannot generate code on demand, as it is needed, which means that we spend time compiling code we might not need but also that we cannot integrate with monomorphization. And so forth. I think we should integrate procedural macros more deeply into the compiler. 2 I’d like macros that can inspect types, that can generate code in response to monomorphization, that can influence diagnostics 3 and lints, and maybe even customize things like method dispatch rules. That will allow all people to author crates that provide awesome interop with all those languages, but it will also help people write crates for all kinds of other things. To get a sense for what I’m talking about, check out F#’s type providers and what they can do. The challenge here will be figuring out how to keep the stabilization surface area as small as possible. Whenever possible I would look for ways to have macros communicate by generating ordinary Rust code, perhaps with some small tweaks. Imagine macros that generate things like a “virtual function”, that has an ordinary Rust signature but where the body for a particular instance is constructed by a callback into the procedural macro during monomorphization. And what format should that body take? Ideally, it’d just be Rust code, so as to avoid introducing any new surface area. So, it turns out I’m a big fan of Rust. And, I ain’t gonna lie, when I see a prominent project pick some other language, at least in a scenario where Rust would’ve done equally well, it makes me sad. And yet I also know that if every project were written in Rust, that would be so sad . I mean, who would we steal good ideas from? I really like the idea of focusing our attention on making Rust work well with other languages , not on convincing people Rust is better 4 . The easier it is to add Rust to a project, the more people will try it – and if Rust is truly a better fit for them, they’ll use it more and more. This post pitched out a north star where How do we get there? I think there’s some concrete next steps: Well, as easy as it can be.  ↩︎ Rust’s incremental compilation system is pretty well suited to this vision. It works by executing an arbitrary function and then recording what bits of the program state that function looks at. The next time we run the compiler, we can see if those bits of state have changed to avoid re-running the function. The interesting thing is that this function could as well be part of a procedural macro, it doesn’t have to be built-in to the compiler.  ↩︎ Stuff like the tool attribute namespace is super cool! More of this!  ↩︎ I’ve always been fond of this article Rust vs Go, “Why they’re better together” .  ↩︎

0 views
Ivan Sagalaev 2 years ago

On Kotlin

I've been writing code in Kotlin on and off over a few months, and I think I'm now at this unique stage of learning something new when I already have a sense of what's what, but not yet so far advanced so I don't remember beginner's pain points. Here's a dump of some of my impressions, good and bad. We were not out to win over the Lisp programmers; we were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp. — Guy Steele Kotlin drags Java programmers another half of the rest of the way. That is to say, Kotlin doesn't feel like a real functional-first language. It's still mostly Java with all its imperativism, mutability and OO, but layered with some (quite welcome) syntactic sugar that makes it less verbose and actually encourages functional style. Where it still feels mostly Java-ish is when you need to work with Java libraries. Which is most of the time, since the absolutely transparent Java interop doesn't make writing Kotlin-flavored libraries a necessity. For starters, you don't have to put everything in classes with methods any more. Plain top-level functions are perfectly okay. You also don't need to write/generate a full-blown class if what you really need is a struct/record. Instead you just do: These have some handy features (like comparability) implemented out of the box, which is nice. And then you can pass them to functions as plain arguments, without necessarily having to make them methods on those argument's classes. Like other newer languages (Swift, Rust) Kotlin allows you to add your own methods to existing classes, even to built-in types. They are neatly scoped to whatever package they're defined in, and don't hijack the type for the entirety of the code in your program. The latter is what happens when you add a new method to a built-in class dynamically in Ruby, and as far as I know, it's a constant source of bad surprises. It doesn't require any special magic. Just keep in mind that is not really different from , only the name of the first parameter is going to be , and it's going to be available implicitly. This, I think, is actually a big deal, becasue looser coupling between types and functions operating on them pushes you away from building rigid heirarchies. And by now I believe most people have realized that inheritance doesn't scale. So these days the only real value in having over is the ability to compose functions in the natural direction: … as opposed to Yes, I know your Haskell/OCaml/Clojure have their own way of doing it. Good. Kotlin has chaining. Kotlin uses and for declaring local data as immutable and mutable, respectively. is encouraged to be used by default, and the compiler will yell at you if you use without actually needing to mutate the variable. This is very similar to Rust's and . Unfortunately however, Kotlin doesn't enforce immutability of a class instance inside its methods, so it's still totally possible to do: … and have internal state changed unpredictably. Kotlin is another new language adopting "everyhing is an expression" paradigm. You can assign the result of, say, an statement to a variable or it. This plays well with a shortened syntax for functions consisting of a single expression, which doesn't involve curly braces and the keyword: You still need in imperative functions and for early bail-outs. This is all good, I don't know of any downsides. I think Kotlin has easily the best syntax for nameless in-place functions out of all languages with curly braces: You put the body of the function within , no extra keywords or symbols required. If it has one argument (which is very common), it has an implicit short name, . This one is really cool: if the lambda is the last argument of the accepting function, you can take it outside the parentheses, and if there are no other arguments, you can omit the parentheses altogether. So filtering, mapping and reducing a collection looks like: Note the absence of after the first two functions. The line with is more complicated because it does have an extra argument, an initial value, which has to go into parentheses, and it also has a two-argument lambda, so it needs to name them. Many times you can get away with not inventing a name for another temporary variable: takes the object on which it was called ( in this case), passes it as a single argument to its lambda, where you can use it as, well, , and then returns whatever was returned from the lambda. This makes for succinct, closed pieces of code which otherwise would either bleed their local variables outside the scope, or require a named function. This reminds me of Clojure's , and Kotlin also has its own idiom similar to which is a variant that only works when the value is not : If the result of is the operator would safely short-cirquit the whole thing and not call the block. Speaking of , it's actually one of no fewer than five slight variations of the same idea. They vary by which name the object is passed inside the lambda block, and by what it returns, the object itself or the result of the lambda. Here they are: Technically, you can get by with only ever using , because you can always return explicitly, and the difference between and is mostly cosmetic: sometimes you can save more characters by omitting typing , sometimes you still need it to avoid things like , so you switch to using . The real reason for all these variations is they're supposed to convey different semantics . In practice I would say it creates more fuss than it helps, but it may be just my lack of habit. And no, I didn't forget about the fifth one, , which is just a variant of , but you pass the object in parentheses instead of putting it in front of a dot: I can only probably justify its existence by a (misplaced) nostalgia for a similar from Pascal and early JavaScript. And there's a reason nobody uses it anymore: the implicit was a reliable source of hard to spot bugs. By the way, this sudden language complexity is something that Lisps manage to avoid by simply not having the distinction between "functions" and "methods", and always returning the last expression from a form. "An elegant weapon for a more civilized age", and all that :-) That one caught me off guard. Turns out there's a difference on what kind of value you call , and such. Calling them on a does not produce a lazy sequence, it actually produce a concrete list. If you want a lazy result you should cast a concrete collection to first: That's one more gotcha to be aware of if you want to avoid allocating memory for temporary results at every step of your data transformations. In Python, tuples are a workhorse as much as dicts and lists. One of their underappreciated properties is their natural orderability : as long as corresponding elements of two tuples are comparable with each other, tuples are also comparable, with leftmost elements being the most significant, so you have: This is tremendously convenient when sorting collections of custom elements, because you only need to provide a function mapping your custom value to a tuple: Kotlin doesn't have tuples. It has pairs , but they aren't orderable and, well, sometimes you need three elements. Or four! So when you want to compare custom elements you have two options: Define comparability for your custom class. Which you do at the class declaration, way too far away from the place where you're sorting them. Or it may not work for you at all if you need to sort these same elements in more than one way. Define a comparator function in place. Kotlin lambdas help here, but since it needs to return a -1/0/1, it's going to be sprawling and repetitive: for all elements, subtract one from another, check for zero, return if not, move to the next element otherwise. Bleh… It's probably to widespread type inference that we owe the resurgence in popularity of typed languages. It's what makes them palatable. But implementations are not equally capable across the board. I can't claim a lot of cross-language experience here, but one thing I noticed about Kotlin is that it often doesn't go as far as, say, Rust in figuring out what is it that you meant. For example, Kotlin can't figure out the type of an item of an initially empty list based on what data you're adding to it: Rust does this just fine: It's a contrived example, but in paractice I also had stumbled against Kotlin's inability to look into how the type is being used later. This is not a huge problem of course… I'm going to bury the lead here and first give you two examples that look messy (to me) before uncovering the True Source of Evil. The first thing are and modifiers for type parameters. There is a long detailed article about them in the docs about generics which I could only sort of understand after the third time I read it. It all has to do with trying to explain to the compiler the IS-A relationship between containers of sub- and supertypes. Like could be treated as if you only read items from it, but you obviously can't write a random into it. Or something… The second example is about extension methods (those that you define on some third-party class in your namespace) that can't be virtual . It may not be immediately apparent why, until you realize that slapping a method on a class is not the same as overriding it in a descendant, but is simply a syntactic sugar for . So when you call it doesn't actually look into the VMT of , it looks for a free-standing function in a local namespace. You put the body of the function within , no extra keywords or symbols required. If it has one argument (which is very common), it has an implicit short name, . This one is really cool: if the lambda is the last argument of the accepting function, you can take it outside the parentheses, and if there are no other arguments, you can omit the parentheses altogether. takes the object as , returns the object takes the object as , returns the result of the block takes the object as , returns the object takes the object as , returns the result of the block Define comparability for your custom class. Which you do at the class declaration, way too far away from the place where you're sorting them. Or it may not work for you at all if you need to sort these same elements in more than one way. Define a comparator function in place. Kotlin lambdas help here, but since it needs to return a -1/0/1, it's going to be sprawling and repetitive: for all elements, subtract one from another, check for zero, return if not, move to the next element otherwise. Bleh…

0 views
Ivan Sagalaev 4 years ago

New pet project

So anyway, I'm making a shopping list app for Android. As I understand, "shopping list" is something of a hello-world exercise of Android development, which may explain why there are so many rudimentary ones in Google Play. Only in my case I actually need one, and I know exactly what I want from it. See, for the past 10 years or so I've been in charge of food supply in our family, which includes everything from grocery shopping logistics, to cooking, to arranging dishes in the dishwasher. And the app is an essential part of the first stage of that chain. Up until recently I used Out of Milk , which someone suggested me a long time ago, and at that time it was probably the best choice. I remember being quite happy to pay for a full version. Over time though it got a little bloated in ways I didn't need and a little neglected in places I cared about. The UI got very "traditional", requiring fiddly unnecessary motions for core functionality. Here's the short list of its wrongs I still remember: Start-up time of several seconds, sometimes overflowing into dozens. I believe my 4-year old phone should be perfectly able to load a shopping list in sub-second time. Adding an item when it's already on the list results in two identical items on the list. (Yes, really.) Auto suggest when adding an item has whatever ordering and limits the amount of displayed results. This meant I could never get "Tomatoes" in there, as they were buried under "Roma tomatoes", "Cherry tomatoes", and a few others with no way to scroll to it. Tiny click target to check an item off the list. I was constantly fat-fingering around those and getting into a different screen. Checking an item off the list puts it into another list below the main one, which you either have to empty all the time, or end up with a huge scroll height. As I understand, the idea was that you could uncheck the items from there to put them back on the list, but that's unrealistic with my catalog of ~ 150 items. "Smart" categorization kept inventing excessively detailed categories leading to several one-item categories clogging up the list. Sometimes unsuccessful synchronization would "forget" added items on the list. Which is funny because I didn't have anything to synchronize with! I probably could spend some time on searching for an app that'd suit me better, but… Look, I'm a programmer. Writing code is what I do! And I wanted to play with Android development since forever, and the recent exposure to Kotlin gave me all the reasons I didn't really need in the first place :-) Here's a laundry list of what I want from a shopping list: Automatic ordering based on the order in which I buy things. I've had this idea ever since I was using Out Of Milk , because ordering manually sucks, and it feels like something computers should be able to do well, right? However it's really not trivial to implement, if you think of it. So it was my main challenge and a trigger to actually start the project. Fuzzy search for suggested items. I'm used to typing 3-4 characters in my Sublime Text to go to every file or identifier in a project. I want the same service here. Smart sorting of suggested items. It could take into account closeness of matching, frequency and recency of buying. Multiple lists with separate histories. Different stores have different order of aisles, and I buy different things in them. A single list won't cut it. Renaming and annotating items . I get annoyed by typos and spelling errors, I want to correct them. And sometimes I want to add a short note to an item (like a particular brand of cheese, or a reminder that I need two cartons of milk this time). Color-coded categories , to give visual aid in scanning what otherwise would be a plain list of strings. They don't have to be terribly detailed. Less of buttons, check boxes and dialogs. I want to interact with the content itself as much as possible. Swiping items off the list instead of clicking a checkbox. Having lists themselves in a carousel, instead of choosing their names from a , etc. Oh, and no settings, if I can get away with it! Undo . It's really annoying to accidentally swipe off something covered by your thumb only to realize it's not what you intended, and now you have no clue what it was. GPS pinning . This is one aspirational feature I'll probably tackle last, if ever. I want to pin a list to a particular geo location, so the app would automatically select it when I'm at this store again. Also, no tracking, ads or other such bullshit. Should be self-explanatory :-) Not having some ugly API SDK making network calls at startup should really help with performance. I actually first started working on it at the end of 2019 and made good progress into 2020… but then something got in the way. Yeah… Anyway, after making an effort to restart the project I'm making good progress again and actually feel really happy about it all! About a month ago I started dogfooding the app and was able to deleted Out Of Milk from my phone (So long and thanks for all the fish!) I've got the first five features mostly done, but there's nothing like actually using it that keeps showing me various edge cases I could never think about. I love this process :-) Crucially, I can now add "Tomatoes" by just typing "t", "m" — and have them as the first suggestion. The app looks pretty rudimentary, as you'd expect at this stage. But really, this time I want to not just fool around and dump the code somewhere in the open, I actually want to make a finished, sellable product out of it. Going to be a fun adventure! (Technically, me and my wife already tried selling my shareware tools at some time in the previous century, but we managed to only sell about two copies, so it doesn't count.) Start-up time of several seconds, sometimes overflowing into dozens. I believe my 4-year old phone should be perfectly able to load a shopping list in sub-second time. Adding an item when it's already on the list results in two identical items on the list. (Yes, really.) Auto suggest when adding an item has whatever ordering and limits the amount of displayed results. This meant I could never get "Tomatoes" in there, as they were buried under "Roma tomatoes", "Cherry tomatoes", and a few others with no way to scroll to it. Tiny click target to check an item off the list. I was constantly fat-fingering around those and getting into a different screen. Checking an item off the list puts it into another list below the main one, which you either have to empty all the time, or end up with a huge scroll height. As I understand, the idea was that you could uncheck the items from there to put them back on the list, but that's unrealistic with my catalog of ~ 150 items. "Smart" categorization kept inventing excessively detailed categories leading to several one-item categories clogging up the list. Sometimes unsuccessful synchronization would "forget" added items on the list. Which is funny because I didn't have anything to synchronize with! Automatic ordering based on the order in which I buy things. I've had this idea ever since I was using Out Of Milk , because ordering manually sucks, and it feels like something computers should be able to do well, right? However it's really not trivial to implement, if you think of it. So it was my main challenge and a trigger to actually start the project. Fuzzy search for suggested items. I'm used to typing 3-4 characters in my Sublime Text to go to every file or identifier in a project. I want the same service here. Smart sorting of suggested items. It could take into account closeness of matching, frequency and recency of buying. Multiple lists with separate histories. Different stores have different order of aisles, and I buy different things in them. A single list won't cut it. Renaming and annotating items . I get annoyed by typos and spelling errors, I want to correct them. And sometimes I want to add a short note to an item (like a particular brand of cheese, or a reminder that I need two cartons of milk this time). Color-coded categories , to give visual aid in scanning what otherwise would be a plain list of strings. They don't have to be terribly detailed. Less of buttons, check boxes and dialogs. I want to interact with the content itself as much as possible. Swiping items off the list instead of clicking a checkbox. Having lists themselves in a carousel, instead of choosing their names from a , etc. Oh, and no settings, if I can get away with it! Undo . It's really annoying to accidentally swipe off something covered by your thumb only to realize it's not what you intended, and now you have no clue what it was. GPS pinning . This is one aspirational feature I'll probably tackle last, if ever. I want to pin a list to a particular geo location, so the app would automatically select it when I'm at this store again. Also, no tracking, ads or other such bullshit. Should be self-explanatory :-) Not having some ugly API SDK making network calls at startup should really help with performance.

0 views
Ivan Sagalaev 4 years ago

Status update: 2020

Pretty sure I'm in the minority on this one, but this year was actually a good one for me! One of the best in a while, to be honest… There's nothing good about this, and we all could do without it. But even then, being introverted probably helped me to fare better than most with the whole sitting at home thing. Also, nobody of my family and friends had died or had any severe health problems. So I'm filing it under the "could be worse" category. Unlike many, many people who lost their jobs this year I actually got a new one. I was lucky enough to wrap up my interviewing and even do an onboarding week in New York in the first week of March, right before the quarantine. I distinctly remember a conversation with the manager of my favorite breakfast place in NY about the virus: she was worried, and I was completely dismissive about the severity of the thing, saying that it's going to be gone soon like another flu, and the probability to catch it was really low. Yeah… Didn't take long to realize how wrong I was! So anyway this is now my third job in a row where I'm working remotely from West coast on a New York based company :-) This time it's Datadog . Dealing with Python, TypeScript, React, Kubernetes, etc. Nothing out of the ordinary. But going from a household with no income to having two people with income obviously sweetens the deal quite a lot! It was a long process, but now it is fair to say that maintenance of the library is finally out of my hands. I still own the domain name and do occasional merges and fixes to the site code which Josh asks me to, but I'm so very glad the project hasn't died with me losing the interest! This is something that makes me really, really happy. After quite a few years of hiatus I made enough time to go back to programming something for myself. Not nearly as regular as I'd like to, but it is happening, and it's immensely satisfying! This time it's an Android app ( in Kotlin , of course), and the one I wanted to make for myself for more than 5 years: a shopping list. It may sound totally lame but I don't care :-) And I'll definitely blog about it in some more details. One thing that made it possible is that our school has smoothed out the remote learning process enough so that me and my wife don't have to babysit our 3-rd grader through the day. She does everything mostly by herself, so we have time to actually work during the day and I, consequently, have time to do other stuff in the evenings. This was the best year ever, literally! After recovering from yet another of innumerable injuries in the beginning of the year I'm back to running fast, and setting personal bests on both 6 and 13 miles. This is probably in part due to the new running shoes , too. We used to play board games a lot with different friends and colleagues back when we lived in Moscow, but after everyone moved everywhere we pretty much only played once a year when we visited our oldest friends for the New Year celebration. But this year we realized our kid is old enough to be interested in board games, so we went big on that and dedicated a whole room to it! We dug out the old games we hauled with us from Russia and we bought some new ones. And now we have some family fun most nights. I have to say, our girl is scary good at Munchkin!

0 views