My Internship at Jabra
Last September I started as a software engineering intern at Jabra. They're a headphone/earbud brand owned by parent company GN that makes a variety of enterprise and consumer products. GN also owns brands in the gaming and hearing aid spaces such as SteelSeries and ReSound.
I'm with the research and development group based out of Dover, NH. They focus on enterprise wireless headsets for front-line workers and truckers. They used to be part of a company called VXi until it was acquired by GN in October of 2016.
What I've Done
I've been incredibly grateful to the team I work with. At the start I worked hard to get up to speed quickly. While an internship is often a learning experience, I also wanted to make sure I was a productive contributing member of the team.
They noticed the drive and level of competence I displayed, because not long after, they gave me a lot of autonomy to do my work. Not only did they trust me to build things without oversight, but they valued and listened to my advice and feedback on matters within my purview. I was not expecting it, but on multiple occasions I made recommendations that were taken seriously and accepted.
Another thing I've enjoyed about this internship is the variety of projects I get to work on. It's a small team that uses the joint-development model to make their products. This means that while the software team is focused on firmware development, they also need to know enough about other domains to coordinate the work of outside contractors. As an intern, I've been able to work on everything from firmware to mobile, web, and DevOps development.
Firmware
I've been primarily focused on new product firmware development. Things like UI, which for an physical product means how the product reacts when you do things like press a button or connect a Bluetooth device. I've also worked on features related to production line calibration and testing.
As products are built on the production line, they're "flashed" (loaded) with the firmware that controls their microprocessors. After assembly, they need to be tested to ensure they're working properly, and some components may require calibration. The firmware needs to work in concert with the production line equipment to test certain features and to calibrate the product as necessary. One of the projects I've been working on is building the functionality necessary to test and calibrate the product on the assembly line.
Simultaneously while developing the firmware for our product, the production line people are preparing for mass production. As part of my work, I've had to coordinate with peers overseas to make sure the production line calibration and testing features are ready as they start ramping up. This means building critical functionality before production deadlines to ensure the overall launch schedule stays on track.
Digital Signal Processing
I've also had the privilege to take ownership of the digital signal processing (DSP) system on our new product. This system is where audio is processed to improve quality (make it easier to hear or more pleasant) and reduce noise. The DSP microprocessor we're using comes with functionality to configure various types of audio processing. While this is convenient, it lacks certain features we'd like. One of my big projects has been integrating a new DSP platform into our firmware.
It has been a boon to the team's productivity. The new platform is much more portable, meaning the work we do on this product can be transferred easily to another, reducing our development time. Integrating the new DSP platform has also made the process of audio tuning much quicker and more pleasant, similarly reducing development time.
This new platform was entirely new to the Dover R&D team. I've been the person primarily in charge of integrating it into our product, and as a result I'm the go to person for questions. It's been incredibly gratifying to take ownership of a significant portion of the product and be trusted to manage it effectively.
CI/CD
In my hobby projects I've made significant use of GitHub actions to build CI/CD pipelines. The Dover R&D group, being very hardware driven, hadn't yet implemented any sort of CI/CD or DevOps workflow. After I joined, I was able to bring these skills to bear by building CI/CD pipelines for several internal and customer facing software products.
The CI/CD pipeline I made for the new product firmware was particularly helpful. Our firmware has to be built in two parts, one build for the main micro-controller, and another build for the DSP processor. Additionally, there are restrictions on how the DSP firmware can be built, meaning some people have to use prebuilt binaries instead of compiling from source. In the past, this has lead to mistakes where firmware builds were released using outdated DSP binaries, causing issues during the QA process.
I built both nightly and release build pipelines to solve these problems. The nightly pipeline runs....well nightly. It produces development builds that can be used for testing by the development team. The release pipeline runs when we're ready to release a new version of our firmware. During the build, both the micro-controller and DSP processor code is compiled from source, meaning it cannot be outdated. As a result, the release builds are a lot more reliable because they use a standard process. The builds themselves are then distributed to a central repository where they can be retrieved by QA and the rest of the team for further testing and development.
What I've Learned
This internship has been incredibly rewarding. I've repeatedly told my friends and family that even just being paid to write code has been so fulfilling. It's affirmed my decision to leave the nuclear industry, and If my full time job after graduation is like this internship, it'll have all been worth it.
I credit working on my hobby projects a lot to my success. When you're building something from scratch for yourself, you learn to be resourceful and creative in a way you don't from working on school projects. While there have been a lot of similarities between working professionally and working as a hobbyist, there are also a lot of differences. And as any good internship should, it's taught me a lot.
Firmware Development
Most of my experience prior to the internship was with web and cloud native development. Firmware development is as dissimilar to web development as any two pieces of software can be.
For starters, the iteration cycle is much much slower. In web development, the product you're working on is often running locally on your computer. You usually have tools like hot reloading so any change made to the source code is quickly and automatically reflected in your development environment. This means you can iterate quickly, make a small change and immediately see the result.
In firmware development, any change you make requires recompiling the project, which in my experience is slower than building a web project. After, you can't just run it on your computer, you have to plug in your hardware and flash the new build. Then you have to start up the device and perform whatever testing is necessary to see the result of the change you made. Instead of seeing the results immediately like in web development, it often takes several minutes to see what you did.
While no one iteration takes terribly long, it adds up over a work day. And it means you work differently. Instead of working one small change at a time, you often do a few things at once to optimize the time it takes to test your changes. If you make a small mistake it means you have to do the whole iteration loop again. So you inspect your code changes much more thoroughly.
Software Development Life-Cycle
In professional software development there are more stakeholders and the risks associated with a project taking longer or going over budget are higher. There are also a lot more people working together on the project. Compared to a hobby project, professional software development requires more coordination and discipline.
In software engineering, this manifests at the software development lifecycle. The project doesn't just start by hacking out source code off the cuff. Instead you start by narrowing down what your requirements are, then coming up with plans to test and verify you've met your goals. This can be visualized by things like the waterfall or V models.
This is my first experience working with detailed requirements and testing documents. The Dover R&D group takes these things very seriously, to the point where it was the first thing I was ever trained on. Detailing your requirements ahead of time and refining them as you go helps you prevent wasted time and development effort because you can be sure you're building the right things. It also helps guide the roadmap because you can clearly see all of the things you need to do.
Having a testing plan that clearly lays out whether or not requirements are being met is similarly powerful. By iteratively testing your product, you not only ensure a high standard of quality, but you get a good sense of how the project is coming along. Testing helps you see if your schedule is on track or if existing features broke during the development of new features.
After working in an environment with detailed requirements and testing, I ended up integrating this workflow into my master's capstone project at school. At the start of the semester, I suggested to my group that we lay out our requirements and iteratively refine and test them as we go. I saw how useful it was at work and wanted it in my own projects as well.
New Technologies
Before the internship I wasn't scared of C, but I hadn't worked on any decent sized projects with it. This was the first time I was developing mainly in C and it's been interesting. C is a great language and much of the modern world is built on it, but it's missing a lot of modern conveniences I'm used to. The things I miss most are modules and classes.
C has an antiquated module and code reuse system. Whereas in a language like Python, you can use directly include another source file (or a symbol within that source file) by module name, C requires the use of header files and forward references. In my experience, I've found this makes it cumbersome to organize and split up your source files. It also makes it harder to understand exactly where a certain function or variable originates. I've had this complaint with other languages too, but I think one thing a good module system should do is make it clear where things are from.
Lacking classes, C makes it harder to use a lot of the design patterns I've learned over the last few years. Some of them are easy, the singleton pattern can be quickly approximated. But others like the State pattern are harder. Thinking C++ could be used as a drop in replacement for C, I tried implementing some functionality in C++. What I found is that, while it interoperates with C more than most languages, C++ is not a 'drop in' replacement. The build system did NOT like mixing C and C++, primarily because the SDK we're working with was not written to be interoperable.
Other than working with C, I had exposure to a lot of new technologies. The new product I was working on uses Bluetooth and a real time operating system (RTOS). These were all very new to me, along with DSP development. What I found in these cases is that I often had prior experience that made the learning process easier.
For example, I took a networking course in my master's program and I've done a lot of networking related hobby projects. This helped me understand how Bluetooth works at a protocol level. Similarly, working in a concurrent RTOS environment was made easier by my prior studies in concurrent programming and the concurrent programming I've done in my hobby projects. DSP programming was made easier because of my audio engineering experience in undergrad (I was the chief engineer of the student radio station at UMass Lowell).
Multi-Disciplinary Environment
The new product I was working on was a physical electronic. It wasn't a pure software product like Microsoft Excel or Facebook. This mean I've done a lot of collaboration with engineers from other disciplines. In particular, I've worked closely with the electrical and acoustic engineers on the team. Each discipline approaches problems differently and it's been useful to see new ways of thinking. Even some of the software engineers on the team studied electrical engineering in college, and they approach problems differently from someone who studied computer science. It's been a very interesting experience.
One of the most valuable skills I've been able to refine is communication. Working on a multi-disciplinary team, you can't assume everyone knows the same jargon or understands the same concepts you do. So you have to get good at communicating key ideas to people who might be working from a different context / background.
Get an Internship
One of the most prudent decisions I made in grad school was going for this internship. I've learned so much from it and it's been a fulfilling experience. I think this advice applies broadly to anyone in school, but it's important to get experience in the field you want to work in. It helps you see more clearly what you'd enjoy doing after graduation. Even if you're planning on staying in academia, getting a job as a teaching assistant or doing research will give you a much better sense of direction and affirm the decisions you're making. Or it could show you that you actually want something completely different.
It looks good on a resume too, but more importantly, you learn the skills necessary to succeed at a full time job. It makes you a more well rounded software engineer. My internship ends this Friday and I'm excited to use these skills again at my next job.