I've found that GitHub Copilot can be a great assistant
both for personal and work projects. I'm Pamela, a cloud
advocate at Microsoft focused on Python. After just a few
months of using Copilot, I find myself using it more
and more, and I want to share some tips with
you. If you're new to Copilot, be sure to watch
this video here. There's also a great video by my
colleague Alfredo.
About using Copilot to turn a command LINE app into
a fast API app. This video is all about best
practices for prompting Copilot. My examples are in Python, but
the practices apply to all languages on a high level.
Remember these two things, one, provide context and two, be
predictable. Let's explore some situations to see what I mean
by that.
Let's start with an example of just a single file
Python program to process a bit of JSON. Now, one
way that I'm going to provide context to Copilot is
by keeping that JSON open in another tab in viscode
so that that gives a good clue that this is
what we're working on. I'm also going to start my
file with a high level comment about what we're doing
description This file processes talks dot JSON.
Now, a nice thing to do is to start off
with imports. If we know for sure that there's a
particular module or package that we're using, it's really good
to start off by importing it, because that gives Copilot
really nice context to decide how to manipulate things because
there's many different ways of doing something in Python. But
we're going to give it a little heads up that
this is how we want to do it. So I
will go ahead and import JSON like it suggests, and
then I'm done with my imports and I want to
read the file in.
And I like everything suggested here. The only thing I'm
going to change is this variable name. As a general
best practice, it's nice to have really specific variable names
that can give more hints about what a particular variable
is.
So instead of data, which could represent anything, you know,
any data type and any sort of thing, I'm going
to say talks, and I'm even going to use a
Python type annotation to specify that this is a list.
It's not necessary to use a type annotation, but if
you're in a language where you do have types or
type hints, it's a nice thing to do. Now, in
order to process this and manipulate in some way, I'm
actually going to write some functions.
We don't have to write functions, but I like to
write functions. It helps me keep code more organized and
it's easy to test them. Well, I'm going to make
a function here that's going to filter talks by tag,
and I gave it a really nice function name. Right?
And just based on that function name, we have a
whole suggestion from Copilot. I like this suggestion. It says
what it's going to take in. And notice that now
it's using type annotations for its suggestions, because it saw
this one type annotation here.
So this is cool because you know I can get
type annotations for free and it says that this is
returning a new list. This is important too because we
could have actually processed the original list, but I did
actually want to return a new list and that's something
that helps to specify as well. One thing that's interesting
here is that it made the design choice to use
a filter function. That's a built in function for Python
which you can filter a list or any iterable and
then turn that back into a list. This is all
fine and good and it should work.
But I actually want to use a list comprehension because
I prefer list comprehensions myself. So in the comment here
I'm just going to give it a little hint to
use a list comprehension and then I'll go in here
and this time it uses list comprehension and I prefer
that. Now let's try it out. Say Python talks, equals,
filter talks by tag, Python talks. Alright, and then we'll
print those out.
It seems like that worked, but I want to be
able to view these results a bit nicer, so I'm
going to make a function for pretty printing talks. So
up here I'll say pretty print talks and let's see
what it suggests. This looks good here. So it titled
by speaker. I don't need speaker because I'm actually the
speaker of all these talks. These are my own talks
I want to just move the tags up into here.
All right, so let's take a look at what this
looks like. OK, that looks nice, except that the tags
are a little nerdy looking because they're actually coming out
as a list. We might want them as, you know,
just a comma separated list without the brackets. So let's
say you know, format tags as, separated list.
So I'm going to go ahead and delete this and
see the suggestion. It really, really wants that speaker there.
I'm going to delete it again. What I should have
done is up here, said title tags and here we
go. Now let's try it out. There we go. That
looks a lot nicer. What we've seen here is that
it's helpful to provide context. Sometimes that context is another
file that's open. Sometimes it's a comment, whether on the
function or the module.
Maybe it's a, you know, a well written function name
or parameter names. Sometimes it's an inline comment just to
guide it along the right path. The more context you
can give to help it figure out which way to
go, that's really going to help it out. Now I'm
going to do a bit of database model design using
the SQL Alchemy Python package. So let's say we're going
to define models for a restaurant application using SQL Alchemy.
Let's start with the imports and let's see what's suggested.
So we see some standard library imports, some SQL Alchemy
imports and hopefully that's enough. So it's suggesting to create
a instance of declarative base class. It's going on to
actually create the models, so for Restaurant.
It's got a table name as it should, and an
ID and a name. Let's also add an address and
a phone. So this did work. However, what's interesting is
that SQL Alchemy recently came out with a new version,
SQL Alchemy 2.0, and it has a fairly different interface
because it is trying to work better with Python type
checkers.
Copilot suggested code using the previous interface, which will actually
still work. It's backwards compatible, but isn't as modern as
it could be. So in cases like this, what I
like to do is actually give Copilot more context by
providing an example straight from the documentation. You know, straight
from the horse's mouth. So I'm going to go to
the documentation for SQL Alchemy and here is their ORM
quick start.
So I'm just going to go ahead and actually delete
all of this and start with their quick start. You
know, Copilot doesn't need a lot of information, you know,
it just needs a hint. So let's leave one of
the classes in here and say we're going to find
model for restaurant with, you know, name, address, phone. Let's
see what it suggests. So this is really cool. This
time everything it suggests is using.
The new way of defining models in Sequel Alchemy 2.0.
So all it needed was a little bit of context.
You know, an additional example to show like, hey, we're
using this more, you know this more modern way of
using Sequel Alchemy and it was able to figure out
how to make a better suggestion. And now I can
delete this example from the docs and just stick with
my restaurant model. So the take away here is that
if you are using a third party package.
It's always a good thing to double check the documentation.
See if your code looks like what you see in
the documentation. If the interface has changed, just give Copilot
a little hint by pasting in some examples from the
docs. That's all it needs to get started. Now let's
use Copilot to add features to an existing code base.
The one I'm working on is a simple restaurant review
app. It's one of our sample apps for Azure tutorials,
so it already has the ability to add restaurants and
to add reviews for restaurants. It's written in the Django
framework, which is a Python web framework which roughly follows
an MVC architecture, more like an MVT architecture, so it's
got models.
It's got views and it's got templates. So what I
want to do is add a new feature to the
site, a discussion forum about food in Django. What you
do in order to create, you know, a new set
of models, views and templates is actually make a whole
new directory. So I can do that. Now let me
drag this out here. Now I'm going to start using
Copilot to write this food form.
Since Django's an MVT framework, you might think like, well,
what should we start with? The models, views or templates?
I'm going to recommend always starting with the models because
everything basically builds on top of those models. So I'm
going to create a new model, a new file models
dot py and I also am going to open the
previous models dot py to give Django some context, and
I'll even bring in the import from here.
So I'm going to say we're creating models for a
discussion forum about food. Users can make posts and reply
to posts. It's going to start suggesting how to define
this model. This looks good. So each post can have
a title, can have a text, and can have a
date. And we could add a string function as well
for easier debugging. Then I also need a reply model
and this one is related to the Post model. So
it did.
Add a foreign key and replies only have text and
they can have a date as well. Next I'm going
to add views dot py because that really builds nicely
on top of models. So we'll say these are the
Django views for the food form app. Actually, I'm going
to go ahead and open the views from the other
part of the site, the restaurant review site, so that
it sees this as an example. Now we'll start with
the imports.
And it has a variety of imports. I don't know
that we're going to use all these. If you know
we don't end up using them, my linterol let me
know that it's a good thing to delete them. We're
definitely going to use the models though, so I'm glad
that it imported those. Now we're going to create the
views, so the index page should probably list all the
posts, and that's actually exactly what it suggested. So it's
grabbing all the posts.
And passing them as template variables into the index dot
HTML template. Of course this template doesn't exist yet, but
we can do that next. Now we want to post
page, right? We want to see a post, so that
page will be passed an ID and it will fetch
the post.
We also want to fetch the replies. So let's get
those replies and see if it amends its suggestion here.
It does so good. We're passing in the post and
the replies. We also need a create post page as
it suggests that is just going to render a form.
We also need a function that can handle the submission
from that page, so that's what's coming next here. Add
post. So this should actually parse the form input and
create a new post object.
So here we see it's getting the title, it's getting
the post text, It's setting all of these, and it
looks like the attribute names do match the column names
from models dot py, so I'm very happy about that.
Finally, we need a way to add a reply. I
think we'll have the add reply form in the post
page itself, but we need to be able to handle
the post that comes. So this should be handling a
POST request. So we see it's getting information from request
posts. It is creating a reply object.
So the big points I want to make with this
example is to think about what order you develop your
code base in. I think it makes sense to start
with database, models and API schemas and then build on
top of those. And also consider what files would be
useful to have open to provide additional context. You want
the files that are showing what particular models are being
built off of. But in this case we also want
to see like oh what does views dot py look
like for another feature of the site?
So there's kind of two types of context that we're
giving in terms of these files. As you can see,
if we provide good context to Copilot and some comments
to guide it along the path, it can really provide
a lot of help in crafting applications, especially when we're
working on web applications that follow predictable structures like MVC
applications.
Do you remember what I said at the beginning? Provide
context and be predictable. Context can be in the form
of open files, comments, import statements, function names, data types,
and sometimes the best context comes from external documentation pasted
in. Predictable program is one that uses standard naming conventions
across variables and files, or even uses a consistent architecture
like MVC. There are some situations where Copilot won't be
as helpful where there isn't enough context or your code
is really just new and different.
But there's so many situations where Copilot can be a
highly productive pair programmer for you, especially when you give
it some extra guidance. Of course, for all code that
you write, whether with Copilot or not, you should always
test it and aim for 100% test coverage at the
minimum. Fortunately, Copilot can help with that too. If you
found this helpful, please like and subscribe. And check out
the other videos from the series too. Thanks for watching.