Browse Category: Software Engineering

A crab reading a book

How I Learned Rust

One question that has come up a few times is “how did you learn Rust?”

I am sharing my path with Rust and the other languages I have experimented with.

I want to emphasise that it is great for any developer to take some of these first steps into other languages.

Once I started on this path, I developed much faster in my primary language and what I was learning.

By learning other languages, I found I could separate the language-specific ideas from the underlying software design principles, making me a better designer and bringing new ideas back to the table.

My Background

First, I wanted to highlight some things that impacted my choices and the elements I spent more time on, as this will be different for you and affect how you approach this.

  1. When coming to Rust, I had already worked in several other languages, and at least in Javascript, I had a significant code base written, so I had gained familiarity with a text-based approach.
  2. I did a bit of C++ and computer architecture at university, so while my systems understanding was poor, I had some fundamentals.
  3. I’m rubbish at working on toy projects on the side.
  4. I am quite unstructured – skimming through the basics quickly and jumping back and forth as needed.
  5. I work for myself, so I don’t have to ask permission.

Getting Started – Do I Want To Learn This

At this point, I started exploring Rust around 4 years ago, so my memory is vague.

I wanted to pick up another systems language to expand what I could deliver to customers. But memory issues in C++ made me nervous.

I kept hearing about Rust on hacker news and decided to look further. My first question is, “do I think this is worth investigating more?”.

I don’t remember exactly, but I suspect this looked like this:

* Finding some basic tutorials and guides to understand the syntax and mental models.

* Following some of these to get something basic working with every shortcut possible.

* Finding libraries related to my work and looking at them on GitHub. Can I make sense of them?

Confirming My Interest – Minor Side Projects

My next step was to ensure my understanding of the fundamentals. I tried to reach a point of knowing what I don’t know and looking for places in my business which would exercise them.

They always have to be a little real to me. Otherwise, I struggle to work on them.

A couple of early examples:

  • I wanted to understand the industrial libraries, and we had issues with a Modbus system – so I created a small application which printed the values from the Modbus device to the command line.
  • I needed to write a LabVIEW driver for a TCP device I didn’t have, so I wrote a simulator in Rust. This project let me experiment with TCP.

In each case, I would know which bit of Rust I wanted to learn (let’s say lifetimes), and so if I hit a problem which needed another part that I didn’t know already, I would either work around it or park the project until I learned it.

This focus was critical:

  • I chose a language feature I wanted to learn.
  • I sidestepped other features I didn’t know.
  • I worked on problems I was already familiar with, so I didn’t also need to learn how to solve the main problem.

This combination meant each experiment had a singular learning goal; otherwise, I tended to get overwhelmed.

Also, note from the examples that they could all be thrown away when I was done – that takes the pressure off!

Committing – Could I do this in Rust?

For the next year or so after deciding I liked Rust, the question was, could I do this in Rust?

Answering this looked like taking projects I had already done, or was doing, in LabVIEW and _designing_ them in Rust. Generally, I didn’t build them all, but I would use the playground or a small project to work out:

  • How would I structure this bit in Rust?
  • What would the types look like in Rust?
  • Is there a library to do x in Rust?

Each of these might have just been a 20-line example solving the major issue in Rust. But it helped me build confidence, especially with lifetimes, which tripped me up the most in these experiments.

This stage also involved absorbing myself in the Rust community, lurking forums, reading blog posts – anything I could to build confidence or find the sharp edge which would stop it from working.

First Steps – Rust Components

At this point, I was convinced I could solve most problems in Rust with enough effort! Now, I needed to gain experience in building larger pieces of code.

Simple questions like how do I structure this in a project? What about CI? Can I be productive?

So, I started looking for changes in projects which could be done in Rust. Not building a whole project but just components of a project where Rust had a clear benefit.

In the end, the key projects that formed this were:

  • A device server in Rust – We needed to use some C++ APIs anyway, so I built a component in Rust which could interface to the device and communicate with LabVIEW through TCP.
  • A web backend in Rust – This was an easier choice as LabVIEW is not an option anyway, so this was displacing Node.js, which was my preferred language for this.
  • Migrating G CLI to Rust for the launcher made it easier to make it cross-platform.

I had to be realistic with my experience and accept I had to take on the additional cost. So, I charged what I would have charged with LabVIEW but allocated double the time to complete it.

I also had to be prepared to throw it away if it didn’t work. However, I did enough prototyping up front to be confident this wouldn’t be the case.

Again, there was a clear benefit to the project to having a separate component anyway. If it was a more minor addition that was just as good as LabVIEW, I stuck with that.

Today – Rust Projects & NI Libraries

That brings me to now – I have confidence that I can do _almost*_ anything I do in LabVIEW in Rust. This confidence means that Rust is now my default in the future.

Rust will be the choice for greenfield projects unless there is a compelling reason not to (and these exist, such as customer commitment to LabVIEW due to other developers or needing to prepare to make the relevant APIs in Rust).

I continue in LabVIEW for existing projects, but a couple have some compelling benefits in Rust. For these, I’ll be migrating new components to Rust with a long-term goal to replace LabVIEW in one case due to significant product benefits.

I’m also working on preparing integrations with key technologies in Rust. I’m working on an FPGA interface library (since I will still use LabVIEW FPGA) and a TDMS library. You can already find my crates for NI System Configuration API and LabVIEW interoperability on crates.io (the Rust package manager)

* .net integration and UIs are still a weak spot.

Logo of the Rust project

Why Rust? (The More Technical Edition)

I’ve written a high-level view of why I got interested in Rust on the Wiresmith Technology site.

After many conversations at GDevCon last week, I felt it would be helpful to put down the technical reasons that Rust appealed to me and how I (and therefore you) could decide what a suitable language is for your test & measurement applications.

What’s In A Language

As I spoke to various people, I got more explicit on the areas I’m evaluating for any given programming language.

  1. Mental/Programming “Model” – This is a hard one to explain, but the simple version is some languages just fit the way you think and some don’t. The model includes technical aspects such as your comfort with manual memory management or imperative vs. functional styles.
  2. Runtime/Deployment Capabilities – Can I run this where I want? Different languages are better suited to environments like the web, docker, microcontrollers, and desktops. There are also performance considerations – is this language’s run time environment capable of high-performance or real-time use cases if you need them?
  3. Tooling – Are the tools around the language high quality and meet your needs? These might be tools like package managers, documentation generators, build automation and orchestration.

These are the three most significant areas I use when examining languages.

Why Look Elsewhere (or where LabVIEW is weak)?

I first started using LabVIEW around 15 years ago. So it isn’t a bad tool. Otherwise, I would have jumped ship long ago!

However, my needs have changed, and I’ve seen new capabilities become available in other languages I envied.

My trajectory has moved me into more projects that I call product development or prototyping. In this area, I found some pain points with LabVIEW:

  • I was moving away from its core in test & measurement, meaning more gaps and less investment in the areas I’m using.
  • The emphasis on software engineering tools has grown as development is done over a more extended period and put into the hands of more users who aren’t familiar with the technology.
  • Only deploying to the desktop or NI’s hardware became restrictive. I’ve had customers where the right solution is an embedded PC or high-performance server, and LabVIEW is difficult to deploy to these.
  • Increasingly, there is a need to integrate into web technologies where LabVIEW is poor—for example, running a web server to collect data.

These are my reasons, and they will not apply to your exact circumstances. This is what I want to emphasise here.

My message is not that everyone should be switching to Rust. In my case, it is a great option. If you are working on an automated test system, for example, you probably don’t have the same pain points, and LabVIEW may work very well for you.

Where Did I Look?

So, lets talk through some languages I’ve investigated and highlight some of their unique capabilities and limitations that might be interesting.

Javascript/Typescript

My first trip into text-based languages was Javascript. Having built a web backend in LabVIEW, it turned out the web server had serious scalability issues at the time. LabVIEW’s web services are challenging to use in anything beyond simple use cases.

Javascript is an interpreted language and generally runs in a very event-driven manner. Being interpreted means it isn’t the fastest (although it’s [JIT compiler](https://medium.com/nerd-for-tech/inside-the-v8-engine-b81aff3eecdb) means it is faster than you might think). Still, it is well suited to web environments where you find it as _the_ language in the browser, and Node.js means you can build pretty complex web servers with it.

Put simply, though, it is not designed to interact with the hardware system, so it is unlikely you will ever see this on a desktop or embedded system (though there are projects to make it a little easier).

The tooling is reasonably good, but it is a little disjointed and moves quickly. Picking up an 8-year-old project recently required a decent chunk of time to modernise everything to the changes that have occurred!

C#

In the LabVIEW NXG days, NI told us that it would be built in C#, and at least to start with, you would need to use C# to extend the environment.

So I decided I wanted to get my head around it, so I wrote the first version of G CLI in it.

C# is a compiled language that runs on a virtual machine-like runtime called the .net CLR (common language run time). It is designed to be extremely powerful for large applications, having been created by Microsoft as a response to Java.

One of the critical characteristics of C# is that it is a garbage-collected language.

Garbage collection means that instead of the user manually controlling memory allocation, a periodic process in the runtime reviews the current objects in memory and frees whichever aren’t used any more.

The big pro is that you don’t have to worry about forgetting to free memory or other memory-related issues as a user. A significant con is that when the garbage collector runs, it can affect the performance of your application. This performance isn’t critical in many applications, but high-performance or real-time applications are negatively affected.

The large runtime also impacts its uses in embedded applications, but it will run in most other places now there is Linux support and container support – it is most commonly found in desktop applications and web applications.

I also didn’t like the exception-style error handling, which has bothered me in many languages after coming from LabVIEW.

For me, the performance may limit its usage, so once NXG disappeared, so did my use of C#. However, this could be hugely powerful in many applications where you use LabVIEW if it ticks some other boxes.

C/C++

Because of where I ended up – it is worth a small shout out to C and C++.

These are systems languages. Systems languages are designed to run “close to the hardware” and are what many operating systems are built with and interoperate very well with.

They are widely supported across different hardware, and pretty much every other language in the world can call libraries created with these since their minimal runtime is generally built into every environment you might run code in (excluding bare metal).

I picked them up because I needed maximum performance for part of a LabVIEW application, so we wrote the processing logic in C and called in from LabVIEW.

A lot of crucial elements overlap with Rust, so why did I skip over these:

  • C is not a particularly expressive language, and I felt like it would get unproductive without built in templating/generics/polymorphism. C++ is better for this.
  • The test library seemed broken again every time I returned to this project. Package management is limited (but improving), and I could see a lot of fighting with tooling.
  • It is very easy to make memory mistakes that cause application crashes. I was happy building small functions in them, but building a complete application without memory issues seemed daunting.

Python

Another language I’ve been using more is Python.

Famously, Python has a huge user base and a wide array of libraries written for it, especially in data analysis.

The tooling is also good, with excellent testing capabilities and a reasonable package manager (with a few quirks!)

However, I found two significant downsides:

  • Python is an interpreted language, which means it has a significant run time and relatively poor performance. Although not as bad as some believe, most heavy lifting is handed off to compiled libraries.
  • I could not get on with the dynamic typing. I completed one web backend in Python and was cursing the typing constantly!

There is a lot of talk about Python in the LabVIEW ecosystem, but I suspect it is overhyped. For me, typing was a big issue that made me very reluctant to build anything significant in it.

Its power is in automation, connecting different libraries quickly and easily. So, in a test environment, it could be great for building individual test steps with a pretty defined scope.

I still use Python for simple automation tasks or interactive data analysis to experiment with different techniques. I know there will be a library somewhere in Python!

Rust

Rust has proven to be my way forward for several reasons. I have been working with it for 3-4 years at this point and found:

  • The language and type system to be expressive and powerful (but some find it too complex and explicit).
  • The memory safety guarantees resolved my no.1 concern with C++.
  • The tooling ecosystem seems to be second to none. Package management, testing, benchmarking, and documentation are all well-covered and ingrained in the language.
  • It is flexible with deployment. It is a systems language, so I can deploy it to a microcontroller or a large server. I’ve also been experimenting with OpenCL, which still needs small portions in C but allows the use of GPUs, DSPs and other hardware accelerators.

These allow me to offer a better service to my customers by leveraging a range of modern hardware without bumping up against limits. Meanwhile, I still feel as productive as I do in LabVIEW.

There are downsides, of course – Rust does require you to manage your memory, which can be a learning curve and makes applications more complex. But this is necessary for some of the deployment flexibility.

Summary – What Is Right For You?

So what should you do? Well, in many cases, sticking with LabVIEW is a good option if you aren’t feeling the same pain that I am. This article is my story, not a roadmap for everyone.

If you are feeling pain, though, hopefully, the summary above will help signpost you to a language that may fit what you need and start doing some research.

Does it fit my mental model? Do I like the community? Have others managed to solve similar problems in it?

This article should help you to start asking these questions.

Branches are For Robots Too

For a long time I  largely ignored branches in git when working on my own.

Quite frankly, as a solo developer I saw no benefit. I understood gitflow and its brethren but it looked like more work for me and no benefit. (again, as a solo developer, I have recommended it to many teams). I just created feature branches when there was a clear benefit.

Recently though, I’ve been looking to up my automation game. For a while now, I have had all commits to my repo for projects run through tests and builds. But I’ve always had a manual release process which had a number of small steps.

I can automate the release processes but I don’t want it to attempt to release every build. I also wanted a place for checks to take place before the final step.

When looking to automate this I realised the same concepts that apply to a team of people, apply to me and my trusty build server. Hence, my adoption of branching.

My Current Solution

What I do now is (mostly) follow a gitflow pattern. I’ve based it on gitflow because it matches my style of software release. To understand why I have added this caveat, check the notes of reflection on the original article at A successful Git branching model » nvie.com and consider how simple you can make it (like GitFlow considered harmful | End of Line Blog).

Once I have a release candidate on develop, I create a merge request to my released branch. (I’ve got no use for released branches right now)

This merge request gives my usual build checks and then I have a checklist covering anything manual:

  • Have I updated the user documentation?
  • Have I updated the version numbers in the VIs (soon to be automated)?
  • Have I run a complete system test?
  • Have I tested this with the end user?

Once I approve the merge request, the CI scripts can detect a merge to the released branch and will build and publish the installers. I’ve also got it making the release tag in Gitlab for me.

So remember, robots are team members too!


By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close