Ask HN: How to learn proper systems programming?

336 points by systems_learn ↗ HN
I am a software engineer for the past 10 years, and did frontend and backend development. I am learning Rust at the moment and have the following books:

- "The Linux Programming Interface"

- "Systems Programming with Linux"

- "Adavnaced UNIX Programming"

What I struggle with: How to get exposure to projects to learn for a future job? I had a Rust job for around half a year, where people build web servers and came from a C and C++ background. Half of the stuff they wrote I didn't understand (flushing, opening another channel just for logs so we don't fill up the other ones etc. etc.).

Now I wonder how I can get access to this type of information, how to properly learn it?

96 comments

[ 3.2 ms ] story [ 163 ms ] thread
Find an open source project.
I can't give you specific advice, but in general it sounds you are already on the right track. You are basically exposing yourself to this new stuff, it raises questions that you want to have answered and you reach out to a community to know more. The stuff they wrote you don't understand YET is part of the journey and if you continue to practice work in that domain, you will be able to connect the dots. TL;DR My advice is, be fair to yourself, accept it's a new domain and be resilient and continue despite the difficulties. I hope a systems programmer will give you more specific advice.
If you're interested in systems programming with rust then i can recommend "Rust in Action" by Tim McNamara [1].

You've found some pretty good resources already by the looks of it though.

[1] https://www.manning.com/books/rust-in-action

Thanks for recommending my book Sam.

Author here - please feel free to ask any questions :)

Find the kind of system you'd be interested in working on and start building one yourself. For me it was a game engine + an editor for it, but it could be anything you find the motivation to build.

Start with a book or a few texts/tutorials on the subject and begin building. Along the way you'll find the questions and choices involved. Find the answers from the internet or books. This is when I'd recommend some open source projects (not earlier) to see how they solved the specific problems. If you just go into an open-source project you won't have an understanding of the problem, just the answers, so it won't help you nearly as much.

> I had a Rust job for around half a year, where people build web servers and came from a C and C++ background

I don't think this is system programming rather network programming.

You should try embedded or try to write drivers

Better yet write a mini OS your own that interface with hardware

Edit: Wow, I'm getting down voted. I guess political correctness

Drivers are not all system software there is.
I meant to be hardware drivers like Display drivers.

The OP asked about System Programming not System software.

Driver is an interface and you can write application software on top of it.

> The OP asked about System Programming not System software.

System programming obviously involves writing system software.

Fuck off, moron! Rust assholes have no clues about reality!!
Web servers would be counted as systems software by most people. I've been a 'systems' person my whole career, part of the system community, publishing at systems conference and doing work in a systems research group, and I'd count web servers as systems and so would most people I know.
> I don't think this is system programming rather network programming.

This is probably why you are getting downvoted. Squabling about semantics / gatekeeping what counts as systems-programming isn't useful. It probably doesn't answer OPs question, and it is rather rude to assume that what OP meant by "systems programming" is wrong just because it is different from what you mean by "systems programming".

edit: maybe it was your dead comment that caused the downvotes.

in what world could the negative response to your pedantic and gatekeeping comment be considered "political correctness"
I think a good approach to learning systems programming would be to find a piece of hardware, read through its datasheet, and attempt to implement its driver. Or program a microcontroller in rust. Or try to get "hello world" to display on a PC operate without an OS.

There are a lot of neat, and not-too-intimidating things that will give you a good appreciation of the techniques used in systems programming you don't see in other areas. Eg reading technical documentation (datasheets, Reference Manuals etc), reading and writing registers, familiarizing yourself with memory layout, and communications protocols. Writing a HAL to see how you can abstract over register writes to make high-level code.

In other words, I agree, and don't think this post's parent was gatekeeping; it's the definition I had assumed as well.

A couple of books that are often recommended for understanding how to make robust software:

- Release It! (https://pragprog.com/titles/mnee2/release-it-second-edition/)

- Designing Data-Intensive Applications (https://dataintensive.net/)

I would suggest finding an open source project of interest and taking a deep dive into its code and documentation to understand how it works and why it was built that way.

Which reminds me, this should help with that: The Architecture of Open Source Applications (http://www.aosabook.org/en/index.html)

Some books I learnt off and still seem to be around

Modern Operating Systems by Tanenbaum is a good theory book - this will probably answer your questions about flushing etc

for down and dirty:

Advanced Programming in the UNIX Environment

TCP/IP Illustrated, Volume 1 (2 and 3)

There are two books that taught me how systems work.

- One system in isolation - Operating Systems: Three Easy Pieces. Covers persistence, virtualisation and concurrency. This book is available for free at https://pages.cs.wisc.edu/~remzi/OSTEP/

- Multiple systems, and how data flows through them - Designing Data Intensive Applications. Covers the low level details of how databases persist data to disk and how multiple nodes coordinate with each other. If you’ve heard of the “CAP theorem”, this is the source to learn it from. Worth every penny.

More on why these two books are worth reading at https://teachyourselfcs.com

I misread the first line of your bullets and thought the titles were:

- One system in isolation

- Multiple systems, and how data flows through them

Which would be really good names for a two part series.

I agree with the Operating Systems Three Easy Pieces textbook. It was used in one of my courses in college and even as a bad dev then, it made me appreciate a lot of things I take for granted, as well as C. Although once I got to the scheduler, mutexes, etc I lost interest haha. But making my oen linked list was a very fun exercise.
(comment deleted)
First off, don't worry. You already have all the necessary tools you need.

Although the language you use to learn system & network programming doesn't matter much, it is better if you use C or C++ to practise and learn. This is because the kernel itself is written in C and exposes system calls that can be used directly from a C/C++ program. That said, "The Linux Programming Interface"(I am personally reading it) is a really good book. It talks a lot about how one should go about using system calls to get things done by the kernel. Make sure to read a little every day and try out the examples by writing C/C++ programs.

I recently realized that TLPI doesn't talk much about why are things the way they are(a very good example would be virtual memory and related stuff). You should refer some theoretical book for this. I suggest you go with "Operating systems" by Deitel & Choffnes.

Read man pages and practise using the libc/kernel APIs. For example, if you want to know about flushing, read 'man 3 fflush'. This might be needed when you want to flush all the input/output data that has been buffered by the C library before you can get fresh input from stdin. For example, if prompts are buffered, you definitely don't want to "scanf" before you have flushed the buffers. If you want to learn network programming, read chapters related to socket and refer 'man 2 socket'.

You will eventually get to a point where you will be able to connect all the dots(APIs) and be able to figure out what exactly you will need to get some problem solved.

Finally, don't learn for a future job. Learn for yourself. This will help you in the long run.

There are a few good YouTube channels of strong system programmers doing live coding. Watching videos takes time, but you can pick up lots of techniques, big and small, by watching people work.

Since you're looking at rust, https://www.youtube.com/user/gamozolabs/videos could be a good fit.

Any channels you can recommend that have live system coding in C?
Pick an operating system, e.g. Haiku(BeOS), Plan9, Net/Open/Free-BSD. Download the source code and dig in. Read the source, the comments, commit logs and email threads. IMO Linux has gotten too big and complex due to having to support so many processors and devices.

Most existing systems programming is in C/C++. Rust is new and there isn't much battle hardened code out there.

Plan9 is known for having very accessible code.
What worked for me is trying to develop my own kernel. This might be too low-level for you, but it helps immensely to dispel the magic around how code gets executed by the CPU and the OS. You'll learn how the OS achieves protection from user programs, what are interrupts and how does the OS handle them, what are processes and threads and how does the OS schedule their execution, how virtual memory works (segmentation/paging), how the program is laid out in memory (code, data, heap, stack), how runtimes like the C runtime manages memory and links your code to OS syscalls, how dynamic linking works, what is an ABI, what is a calling convention, how does the compiler, the linker, and the OS know what each should do? How memory mapped file access works, etc. I can keep going, but you get the picture.

From there, you'll know where to go next based on what you've learned so far.

My recommended reading list is:

[1] Operating Systems: Three Easy Pieces https://pages.cs.wisc.edu/~remzi/OSTEP

[2] Intel Software Developer Manuals (especially volume 1 and 3A) https://software.intel.com/content/www/us/en/develop/article...

[3] OSDev wiki https://wiki.osdev.org

Start using your operating system directly instead of relying on libraries to do things for you. Learn Linux system calls and use them for everything. A great way to do this is to compile your C code in freestanding mode and with no libc. You'll have to do everything yourself.

It is easy to get started. Here's a system call function for x86_64 Linux:

https://github.com/matheusmoreira/liblinux/blob/master/sourc...

With this single function, it is possible to do anything. You can rewrite the entire Linux user space with this.

The Linux kernel itself has a nolibc.h file that they use for their own freestanding tools:

https://github.com/torvalds/linux/blob/master/tools/include/...

It's even better than what I came up with. Permissively licensed. Supports lots of architectures. There's process startup code so you don't even need GCC's startfiles in order to have a normal main function. The only missing feature is the auxiliary vector. You can just include it and start using Linux immediately.

You can absolutely do this with Rust as well. Rust supports programming with no standard library. If I remember correctly, the inline assembly macros are still an unstable feature. It's likely to change in the future though.

Hello there I have quite similar background. (10 years experience, in backend and native android development). Most of the comments already contain good advice. Systems Engineering takes time. I followed long route. I initially took some course in digital logic, and computer architecture and than later took following OS courses.

1. https://pdos.csail.mit.edu/6.S081/2020/schedule.html (check video links and do all the lab assignments)

2. https://www.youtube.com/watch?v=dEWplhfg4Dg&list=PLf3ZkSCyj1... (based on old MIT 6.828)

3. Networks Review (self study)

Somebody mentioned Intel manuals in the comment (those are really helpful)

These courses helped alot. I would suggest to take some firmware and device driver development course as well. My conclusion is that, these are tough skills and the learning process can be accelerated if you can find some entry level position in a small company which do this kind of work.

I just completed the xv6 projects for that course and they were damn difficult, but taught me a lot. I highly recommend it.

The only thing I missed was support for when I really ran into a wall, but perhaps I just don't know the right irc channel.

I totally agree on that. I tried the old version (intel based). And it to me quite some time to do the projects. But I learned a lot in the process.
If you know folks in your company are writing things you are interested in reach out. Most of those people are happy that someone is taking interest in what they are doing. The information that they will provide will be meaningful and valuable. Use what you learn from those conversations and leverage it in your daily job functions to better position yourself for future roles/jobs/projects.
From personal experience, what made low-level concepts "click" for me was looking at documentation for linkers and the various ELF tools. Once I could see the "ends", it gave me the inspiration to dig into the "means". Ymmv, of course.
If you want to learn Rust for systems programming, first learn C and write something non-trivial in it. Then run it through Valgrind [1] with your test suite. You can also try the sanitizers (AddressSanitizer, MemorySanitizer, UndefinedBehaviorSanitizer, ThreadSanitizer, etc.).

This will teach you what Rust is saving you from and help you understand how it does it.

[1]: https://www.valgrind.org/

> I had a Rust job for around half a year, where people build web servers and came from a C and C++ background. Half of the stuff they wrote I didn't understand (flushing, opening another channel just for logs so we don't fill up the other ones etc. etc.)

I think it's worth mentioning that the majority of topics involved in this type of webserver work wouldn't necessarily be covered by a systems programming book. There's obviously overlap between all of systems programming, networking, and concurrent/distributed systems, but if you plan to focus on web servers, I'd pick up texts on the other topics as well.

Years ago I modified the Postgresql source code (8.xx).

It's something I was terrified of doing.

But once I got in there and started poking around, I realized it was just ordinary plain-vanilla C code. Not C++. Just C code.

With my local copy, I started to hack pg_dump to do something special that we wanted at the time. Even after 30 years of coding, I'm not that especially good of a programmer. But I ended up getting our own special version of pg_dump that did what we wanted at the time and it went into production dumping hundreds of gigs of data every day!

But what I'm not, is afraid. I'm not afraid to try anything.

And that's what it takes to do deep, systems level programming.

Don't be afraid.

Those bits are just bits. And it's just code... and most of it was not written by wizards. Just ordinary people like you and me. Don't be afraid man.

Clone the repo and setup a workable build environment and start tinkering and compiling and running to see what happens.

You would be totally shocked to find out what you can actually achieve.

Those books will only go so far.

I basically came here to suggest the same thing. The biggest part is a mental shift: realize that if you find a bug (or feature you'd like to have) in an open source project that you have the ability to fix it.

The rabbit hole of reading code you go down of reading code when you do that is, I believe, the best real introduction to systems programming. Once you've been doing that for a while, you internalize the idioms. I'd recommend large projects because you're less likely to just end up copying some person or couple of people's quirks, and learning to read large codebases is a major skill in itself. The process of submitting patches often turns into ad hoc mentoring, where you'll be told what you didn't get right this go around. After you've done that for a while, you realize the same things apply to other large systems projects, and you end up exposed to a number of different styles of systems stuff.

> Those bits are just bits. And it's just code... and most of it was not written by wizards. Just ordinary people like you and me. Don't be afraid man.

Code is easy and doesn't scare me. I'm scared about the platform though: code runs on platforms (POSIX, mostly), which are incredibly dated, ill-designed and full of terrible corner cases[1]. There's so many ways to shoot yourself in the foot I'm afraid to do anything sensitive on my own.

«It is not UNIX’s job to stop you from shooting your foot. If you so choose to do so, then it is UNIX’s job to deliver Mr. Bullet to Mr Foot in the most efficient way it knows.»

[1]: Dan Lu's writing on files are a good illustration of that:

- http://danluu.com/file-consistency/

- https://danluu.com/deconstruct-files/

- https://danluu.com/filesystem-errors/

Most POSIX APIs are crap, but most significant systems projects don't code to them directly. Almost all large projects have their own internal (or third party) libraries that either wrap or reimplement the underlying POSIX APIs.

That said, at some point knowing the POSIX APIs does become necessary, but that's usually relevant a bit later when you start becoming interested in modifying the toolkit of large projects.

If you're wanting to start a project on your own rather than jump into an existing project, in a nutshell, if you don't have hard real-time requirements, if you're using C, use glib, if you're using C++, use Qt. There are other libs that are useful for real-time usage (basically things that don't ever have hidden memory allocation), but I'm not familiar enough with that space to recommend one.

How is that not just good old “application programming”?

My own definition of “system programming” is exactly “developing on top of the system” vs “developing in the comfort of a helper library” (and its limits). I consider myself a decent application programmer, but I'm not a system programmer (at least not yet ;).

The OP was talking about Postgres, if you don't know how the pitfalls of write(2), or don't know how to use mmap(2), you're going to have trouble making a database on your own.

Most people don't get into systems programming by writing a database completely on their own, and it's fair to say that the line between application and systems programming is fuzzy.

Here are a bunch of things I would broadly consider systems programming:

- Kernel and driver development

- Low level library development (pretty much anything involving bit wrangling)

- Platform abstraction libraries

- Database development (not usage)

- Message queuing systems

- Daemon / server development

Perhaps the recurring pattern there, and differentiated from application programming is that most of those are tools for other applications, rather than applications themselves. I don't think that all library / daemon development is systems programming, but a whole lot of it is.

I'm coming from a background of having done 5 of the 6 of those groups (though there could obviously be more listed there). For most significant projects, as noted, there will be internal APIs that wrap system APIs (or in the case of the kernel, where the system APIs are totally irrelevant, except for the parts that implement the system calls). Generally someone first jumping into those projects isn't going to immediately start hacking on the internal libraries.

As it were, I have actually written a database from scratch [1]. That database uses Qt and Qt-like APIs internally where possible. There are places in there where you need to know the intricacies of mmap, fsync and similar, but they're compartmentalized to a couple of classes. I'd still call code that isn't in those couple of classes "systems programming".

[1] https://blog.directededge.com/2009/02/27/on-building-a-stupi...

I realize it's unlikely anyone will see this, but to amplify this point a little, I thought I'd poke through the Posgres source (which I'm not otherwise familiar with). By my count, mmap is only called in 4 places, in three files.

The implementation behind this file is one of them:

https://doxygen.postgresql.org/fd_8h.html

That is the actual file API that you'd use inside of Postgres. While the API there isn't going to win any beauty pageants, it's significantly more sane than raw POSIX.

For comparison, this is the interface to mmaped files within my company's internal database:

https://gist.github.com/scotchi/83609f5eb9b98ac3b4b4476ed621...

There's a grand total of 1 call to mmap in all of our source. Most of the time for writing code using mapped files here, all you'd see is the interface above.

My thoughts as well. Send patches in to FLOSS projects.

I sent in a patch to an experienced C programmer a few years ago and in his code review he said about my #ifdef flags - "Typically HAVE_X are about the environment and USE_X are optional features within that environment."

Listening to Linux kernel developers online, they say a lot of people start kernel development with one small patch, or attempting to port some new device or chip to work with Linux. Once their patch gets merged, they sometimes continue to send in patches. The developers say that good contributors tend to not last long as independent contributors, and tend to get pulled into companies who need such programmers.

And there are open jobs for people with such skills ( https://us-redhat.icims.com/jobs/84882/senior-software-engin... )

I want to add to this. People might think they lack opportunities for this exercise because they don't have special requirements out of the open source packages they use. But realize that breaking a piece of code in a controlled manner also needs roughly the same level of understanding as adding a feature.

It could be as simple as a `sleep` in the right circumstances. Maybe your resulting patch is a boring handful like:

    bool cond1 = ...;
    bool cond2 = ...;
    if (cond1 || cond2) {
      sleep(1000);
    }
but you need to read and develop understanding of the code to define the conditions in terms of the program's state. And you also need the same understanding to know where exactly in the code to introduce this snippet. Not to mention compiling it; even with Makefiles, lower-level languages could still be tricky to build.

How this can be useful: Long time ago, we were observing odd behavior from Redis under extremely high load. Of course it did not replicate consistently and when it did, it lasted too short for us to properly observe and make hypotheses. So I had the brilliant idea of installing a custom Redis binary in our test environment that tweaked the odds so that the behavior happened almost consistently, no need to thrash the server. I had to read through Redis source code to make it happen (and added a hell lot of logs too). Plus in the end, it's not quite compiling Linux but, boy, I did compile Redis from scratch!

My perspective:

Anything that's been done by a lot of people, has been done well-enough by some stupid asshole.

I am a stupid asshole.

Therefore, I can probably figure out how to do [thing] well-enough, if it's been done by a lot of people.

It's worked out OK so far.

I have printed out a foreword of an old calculus book, and taped to my wardrobe door. It's a long-ish rant, but it ends with this:

    What a fool can do, another can.
Pretty sure that's Calculus Made Easy, a book which I, as a fool, certainly ought to recognize, and yeah, that's the gist of my approach to "scary" topics. "Have lots and lots of people done it? Then I'll likely be fine, because some of those people were assuredly at least as dumb as I am."

    Considering how many fools can calculate, it is surprising that it should be thought either a difficult or a tedious task for any other fool to learn how to master the same tricks.

    Some calculus-tricks are quite easy. Some are enormously difficult. The fools who write the textbooks of advanced mathematics – and they are mostly clever fools – seldom take the trouble to show you how easy the easy calculations are. On the contrary, they seem to desire to impress you with their tremendous cleverness by going about it in the most difficult way.

    Being myself a remarkably stupid fellow, I have had to unteach myself the difficult, and now beg to present to my fellow fools the parts that are not hard. Master these thoroughly, and the rest will follow. What one fool can do, another can.

http://djm.cc/library/Calculus_Made_Easy_Thompson.pdf
A small counterpoint: I once worked in a code base where small changes would regularly ripple out and cause bugs far far away. You had to traverse a 30-50 source file chain of logic to find what was happening. This was “normal.”

I’m not saying you have to be afraid, just that you sometimes have to tread a bit slower and do a lot of testing as you go until you learn the internals of whatever system you are working on

(Aside: this is what coupling does — you should fear coupling!)

This.

I can relate to this as well. I will share couple of things just to add to this.

I have ~8YoE now. When I was at my first job, I did not have any formal CS degree, I had completed bachelors in commerce and was struggling with masters in computer applications (had year drops). My first job was in a company started by ~7-8 ex-veritas folks, all of them being hardcore system developers. I had dreams of being the same like them some day (yet to happen). ~1 year in this job and I shared my aspirations to become a system developer - I was given a task, implement persistent ram mechanism, something that will persist data in the RAM even after soft reboot, without dumping data on hard drive, using Linux kernel. "what to do" (trick/technique) was told by them, how to do it was left for me. It took me 4 days (2 weekends) to complete this. Over first weekend I learnt how to get Linux source code, add custom syscall, compile kernel etc. On second weekend I actually got to go through the code, find places to add patches, test etc.

I was also afraid before starting and my then boss had said few things like .. "because you think folks sitting in the west are something special, they are not ..", "whole thing is man made. If one man can do it, so can you". It was a matter of going through the code and understand. Do things repeatedly without giving up. Spend long hours, take notes. Once you have the context and that code is running in your head - you get what to do!

I also did the something similar few years after this. I was learning Go and wanted to do something better. I got into delve codebase (debugger for Go) and I patched it to work for cgo binaries. Its a small patch but for that I had to learn delve's architecture + what is dwarf standard and stuff. Context was pretty huge compared to what I needed to patch it. Same story though, I was little afraid thinking - omg! it's a freaking debugger, how am I going to understand all this to make changes. But in fact they are just the same constructs.

Go ahead and jump into some project you use, it helps understanding codebase faster. Read Read Read. Give yourself time to learn the codebase. You will definitely be able to contribute "properly" for that project. Don't be afraid :)

Back when started coding, system programming were books like these ones,

https://www.atariarchives.org

https://archive.org/details/pcinternsystempr0000tisc

Granted they are probably too old, but the concepts of what is actually systems programming is there, you can then get hold of an Arduino or Rasperry PI like device and do your own little OS or bare metal game,

https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/o...

http://www.science.smith.edu/dftwiki/index.php/Tutorial:_Ass...

Or maybe trying your hand at compilers with https://www.nand2tetris.org or given the similarities of Rust with ML, maybe dive into Tiger Book (https://www.cs.princeton.edu/~appel/modern/ml).

Or maybe

https://www.manning.com/books/rust-in-action

https://www.apress.com/gp/book/9781484258590 (Rust for IoT)

Thank you for mentioning Rust in Action.
Follow-up question: how do I learn systems programming on Windows? I know it’s pretty easy to just set up a Linux VM or use WSL2, and I’m prepared to do that if I must, but it would be even easier if I could work in the same Windows environment I normally use. However, from what I’ve seen, practically all guides to systems programming seem to start off by assuming you’re using Linux.

(And by the way, thanks OP for asking this question! I’ve also been wanting to learn systems programming, but I haven’t gotten around to asking yet. And all the suggested resources look fascinating… there goes my university vacation!)

The best start would probably be both parts of Windows Internals:

https://www.amazon.com/Windows-Internals-Part-architecture-m...

https://www.amazon.com/Windows-Internals-Part-Developer-Refe...

These aren't about programming per se, but if you want to do systems programming it helps to have a detailed understanding of the system. :)

After that, specific reading probably depends on the exact task you want to perform, but MS has good documentation and tutorials in many areas. Writing drivers, for example:

https://docs.microsoft.com/en-us/windows-hardware/drivers/ge...

To add on, the windows internals books have exercises with the sysinternals tools. If sitting down and plowing through a doorstop of a book isn't your cup of tea, try picking a chapter or two which sound interesting, skimming them, and doing the exercises.
IMHO getting into the world of malware analysis and reverse engineering could be profitable for both your brain and your pocket. And they force you to go deep from day one.

I do not have the expertise to work on either field but this is something in the plan. The good part is that most malwares are targeting Windows so you get a lot of samples.

This is good advice.

Also, Windows is an excellent way to learn systems programming because the documentation and tooling is so good and things hardly ever change.

There is a wealth of documentation on MSDN for writing device drivers and such. And great tools for remote debugging so you can set up a VM in hyper-v and step through the code from the host system.

Do make sure if you're analyzing malware you do it in a VM on a machine you don't care about having to wipe, and isolate it from the rest of your network.

I've also been trying to learn system programming for a while and what did the trick for me was finding a way to use the C interfaces that UNIX provides.

I've tried to learn C probably 4 times now and I just don't like it. But then I came across LuaJIT ffi which, very easily allows you to use whatever shared library and call whatever syscalls directly and that was a game changer!

After that I decided to test ziglang, which a big part of it's design decisions is interoperability with C, and I'm in love with it! It really feels like anything I would need C for I can do in zig.

If Rust if your jam find a way to call the linux syscalls directly from Rust, not just using a cargo library, but actually importing the appropriate headers and successfully doing an epoll or something.

It will feel like suddenly the man (3) pages all make sense and are extremlly useful!

Good luck!

Get a job in the field. Some places might be willing to take a chance on you if you are a good generalist engineer.

Also, make the case that many things that you learn while doing frontend programming like asynchronous programming are skills that will port over just fine.