与GitHub Copilot合作1周。仅使用Copilot构建一个应用程序

3,985 阅读11分钟

GitHub Copilot是GitHub开发的最新工具,在OpenAI的帮助下自动完成代码。

Copilot通过上下文生成智能代码建议,如文档字符串、代码注释、函数名称,甚至文件名称。然后,它使用所有这些信息来建议代码片段,开发人员可以通过按下键盘上的Tab键轻松接受。

根据Copilot网站,它了解Python、JavaScript、TypeScript、Ruby和Go,以及其他几十种语言,因为它 "在数十亿行公共代码上受过训练"。虽然它目前仍处于有限的技术预览阶段,但有兴趣的人可以注册加入一个等待名单来试用它。

在这篇文章中,我们将探讨Copilot的主要功能,如何只用Copilot建立一个简单的应用程序,以及它的优点和缺点。

Copilot的主要功能

Copilot的主要功能是它的自动完成功能。例如,当输入一个功能描述时,Copilot会在用户完成之前完成整个功能。虽然这种自动完成功能与其他一般的自动完成功能相似,但Copilot的功能更胜一筹。

当继续写代码并添加更多注释时,Copilot开始通过其人工智能能力理解代码的整个上下文。有了上下文,它就能在句子中间自动完成注释。

例如,通过添加一个函数,它生成了整个注释和一个函数;在这种情况下,它想出了最后一个函数应该是一个乘法函数,如下图所示。

Adding A First Function And Comment To See How Copilot Responds

Copilot的另一个很酷的功能是能够看到10个整页的建议,而不是一个单行的建议,并选择最适合的代码。

要做到这一点,在Mac键盘上按^ + Return ,或在Windows上按Ctrl + Enter ,就可以打开建议列表,如下图所示。

Opening Copilot's Suggestions

你能只用GitHub Copilot来构建一个应用程序吗?

利用Copilot的功能,我想挑战一下自己,只用Copilot构建一个小型的应用程序。在这个挑战中,我想创建一个简单的随机报价应用,同时显示报价的情绪。

要做到这一点,我需要遵循一些规则,看看我可以从Copilot中获得多少好处。

首先,如果我遇到问题,我不能在网上搜索,包括使用Stack Overflow或文档。这让我看到是否有可能完全依靠Copilot的建议来创建工作代码。

第二条规则是,我不能自己写任何新的代码。然而,我可以写注释、变量、名称和函数名称来触发Copilot的建议。同样地,我也可以对建议的代码进行小的编辑。

最后,我可以触发Copilot的建议列表并接受其中一个,因为这是一个内置功能。

设置项目

我选择Next.js和React来建立这个项目,因为它们是我最熟悉的工具,可以帮助我更好地评估Copilot的性能。

由于React让开发者在构建应用程序时相当省事,而我想看看Copilot如何管理React组件。

对于Next.js来说,它提供了一个很好的起点,我不需要花很多时间来设置一切,而且它有内置的后端功能,使得它在调用不同的API端点时不会引发CORS错误。

虽然Next.js对于这个小项目来说似乎太强大了,但不需要事先安装其他依赖项,其集成的、易于使用的API功能使它成为这个挑战的好选择。

开发API端点

从开发API端点开始,我想要一个在GET 请求上返回随机报价的报价生成器和一个情感分析端点。情感分析端点需要接收一个字符串作为查询参数,并返回一个情感。

因为我不知道返回值是什么格式,所以我让Copilot来写,看看它能返回什么。

/api/get_quote GET 请求端点

为了使用Next.js创建两个端点,我在api 文件夹中创建了两个文件:get_quote.jsget_sentiment.js 。Next.js就可以根据文件名来创建这些端点。剩下的就是在这些文件中定义处理函数,我让Copilot为我做这些。

对于get_quote 端点,我写了一个评论并选择了一个好的建议。

// get random quote from random API

点击评论,Copilot就会回应一个不同的选项列表,供我挑选。

Writing Command To Trigger Copilot To Get A Random Quote From An API

我选择的建议是以下内容。

const getQuote = async () => {
    const response = await fetch('https://quotes.rest/qod.json')
    const quote = await response.json()
    return quote.contents.quotes[0].quote
}

这个建议起了作用。我检查的其他建议几乎都是坏的,或者需要一个我没有的API密钥。这可能是因为Copilot是在GitHub的开源代码上培训的,有些端点可能已经过时了,这可能会让人感到沮丧。

此外,这个端点返回当天的报价,这意味着每次调用,我都会收到当天的相同报价,这不是我所期望的。相反,对于每个端点的调用,我想收到一个不同的随机报价。

对于这个端点的第二部分,我需要为这个端点创建一个处理程序,调用Copilot已经生成的函数。该处理程序是Next.js在客户端请求端点时调用的函数。

为了做到这一点,我声明了这个函数的名称,看看Copilot是否会建议正确的实现。

Declaring A Function And Its Name To See If Copilot Adds Correct Implementation

而Copilot又给了我一个惊喜。一切似乎都是正确的。

首先,它调用了getQuote 函数,并返回了从网络服务中收到的报价。然后,它将报价保存到常量中,并将检索到的报价返回给客户端的JSON。我唯一需要添加的是.status(200) ,以向客户端发送200 状态代码。

/api/get_sentiment GET 请求端点

对于get_sentiment 功能,我选择了Copilot的建议,不需要改变任何东西。

我输入了以下内容。

// determine if the text is positive or negative

然后,Copilot建议了以下代码,我使用了这个代码。

async function getSentiment(text) {
    const response = await fetch(`http://text-processing.com/api/sentiment/`, {
        method: "POST",
        body: `text=${text}`,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
    })
    const json = await response.json()
    return json.label
}

然而,对于端点部分,我不得不添加.status(200) ,类似于get_quote 端点。

以下是我提供给Copilot的内容。

export default async function handler(req

然后,Copilot建议如下,我选择了它。

export default async function handler(req, res) {
    const sentiment = await getSentiment(req.query.text)
    res.json({ sentiment })
}

Copilot又设法为我们提供了一个可行的解决方案,建议了正确的处理程序,并计算了get_sentiment 处理函数需要返回的内容。这个建议看起来与我们之前的建议相似。

接下来让我们看看Copilot如何处理React组件的生成。

React组件

对于前端,我需要几个指定的React组件和一个带有按钮的React控制器组件。这两个指定的组件需要显示文本:一个是报价文本,另一个是感言文本。

让我们看看Copilot如何处理创建这些React组件。

QuoteTextBox

我从QuoteTextBox 组件开始,它将展示一个简单的报价;我添加了以下评论,看看Copilot会有什么建议。

// React component to show a quote inside a div

const

Copilot推荐了一个简单的函数组件,我完全不需要修改。

const QuoteTextBox = (props) => {
  const { quote } = props
  return (
    <div className="quote-text-box">
      <p>{quote}</p>
    </div>
  )
}

export default QuoteTextBox

Copilot Suggests A Simple Function Component

SentimentTextBox

为了建立情感文本框,我添加了以下评论。

// React component to show sentiment text inside a div

const

对于这个文本框,要找到合适的建议是比较麻烦的,我不得不滚动浏览大部分的建议,直到找到一个能与我的代码配合的建议。

const SentimentTextBox = (props) => {
  // Get sentiment text from props
  const sentimentText = props.sentimentText

  // Return component
  return (
    <div className="sentiment-text-box">
      {sentimentText}
    </div>
  )
}

// Export component
export default SentimentTextBox

清楚地了解对Copilot的期望很重要,因为它只是一个工具,开发者不能只依赖它给出的第一个建议。

SentimentTextBox Suggestion From Copilot

我仍然需要回到这个组件中,将API返回的内容映射成可读的文本。例如,如果网络服务返回neg ,我需要将其映射为Negative

带有按钮的控制器组件

我还需要一个控制器组件来管理所有的逻辑。我创建的前两个React组件只是接收数据并将其呈现在屏幕上,但控制器组件需要管理API调用。

我首先输入了以下内容。

// React component that uses QuiteTextBox and SentimentTextBox and APIs to show quotes and sentiment with a button to generate new quotes.

const

然后,Copilot带来了这个建议。

const QuoteGenerator = ({quote, sentiment, onClick}) => {
  return (
    <div>
      <QuoteTextBox quote={quote} sentiment={sentiment} />
      <button onClick={onClick}>Generate New Quote</button>
      <SentimentTextBox sentiment={sentiment} />
    </div>
  )
}

export default QuoteGenerator

Copilot建议的控制器组件似乎很基本;它缺乏API调用,没有使用正确的道具SentimentTextBox 。然而,Copilot确实提供了正确的结构,它只是需要一些调整来完成它。

然后,我只需要给控制器组件添加功能。我没有传递quotesentimentonClick ,而是要求Copilot生成它们。我还需要一些Hooks来存储从调用API得到的情感和报价数据。

对于Hooks,Copilot马上就知道我需要什么了。为了触发第一个Hook的建议,我开始输入一个评论,Copilot建议了正确的Hook。

然而,对于第二个Hook,我甚至不需要输入评论。我接受了第一个Hook的建议,移到下一行,Copilot立即建议第二个Hook。

Copilot Suggests Two Hooks

虽然端点是正确的,但我仍然需要做一些改变来使它们发挥作用。我必须非常具体地询问我想要什么,否则,Copilot开始建议不同的网络服务。

我希望它只是调用已经创建的端点。此外,当我收到报价时,我需要特别调用getSentiment 端点,并将情感映射为人类可读的文本。

Call And Map getSentiment Hook

这就是我的最终版本,在我这边做了一些小改动之后。

const QuoteGenerator = () => {
    // Hook to store text in state
    const [quoteText, setQuoteText] = React.useState('')
    const [sentimentText, setSentimentText] = React.useState('')

    // Function to get quotes from API /api/get-quote
    const getQuote = () => {
        fetch('/api/get-quote')
            .then(response => response.json())
            .then(json => {
                setQuoteText(json.quote)
                getSentiment(json.quote)
            })
    }

    // Function to get sentiment from API /api/get-sentiment\
    const getSentiment = (text) => {
        fetch('/api/get-sentiment?text=' + text)
            .then(response => response.json())
            .then(json => {
                setSentimentText(json.sentiment)
            })
    }

    // Function to be called when user clicks on button to generate new quote
    const onClick = () => {
        getQuote()
    }


    const mapSentimentToText = {
        'neg': 'Negative',
        'pos': 'Positive',
        'neutral': 'Neutral'
    }

    return (
        <div>
            <QuoteTextBox quote={quoteText} />
            <SentimentTextBox sentimentText={mapSentimentToText[sentimentText]} />
            <button onClick={onClick}>Generate New Quote</button>
        </div>
    )
}

export default QuoteGenerator

最终的应用程序

在对我的简单的报价生成应用程序进行实验后,我发现Copilot提供了足够的帮助来创建一个简单的应用程序。

Final Quote Generator App

我的期望值并不高,最初以为我需要修改大量的代码才能使应用程序正常运行。

然而,Copilot让我吃惊。在一些地方,它给我的建议是无稽之谈,但在另一些地方,这些建议是如此之好,以至于我不敢相信Copilot会做出这些建议。

Copilot的优点和缺点

为了总结我使用Copilot的经验,我整理了使用它的优点和缺点,这样你就可以决定Copilot是否是你可以每天使用的东西。

Copilot的优点

使用Copilot的主要优点是它提供了类固醇的自动完成功能。作为一个自动完成工具,我相信它是目前市场上最好的;没有任何东西能像Copilot一样有用。

Copilot还向开发者展示了解决不同问题的多种方法,这些问题可能不是那么明显。当需要一个代码片段时,10个建议的功能是非常好的,通常可以用来代替Stack Overflow,以提高效率。

总而言之,Copilot使用起来很有趣。对于所有的技术极客来说,这是一个可以玩耍的新东西,它使日常工作变得更加有趣。

Copilot的缺点

虽然它的功能提供了更高的效率,但用户必须记住它是一个工具,而不是人类开发者的替代品。因为Copilot不是万能的,用户不能完全依赖它来完成他们所有的代码。它的大多数建议都需要修改以适应特定的需求。

最后,我注意到Copilot建议将React类用于逻辑性不强的小型组件,而不是使用Hooks的功能组件。因为它是根据GitHub上公开的代码进行训练的,所以Copilot可能会提供一些贬值的编码建议。

总结

GitHub Copilot并不是一个可以听从项目想法并为你编码的东西。它也不会取代开发者的工作。但它可以使编码变得更容易。

GitHub Copilot擅长处理小任务;当你开始要求它处理更复杂的任务时,你往往会得到一些废话。尽管如此,它对于初学者和有经验的开发者来说都是一个非常好的工具。

The post1 week with GitHub Copilot:只用Copilot建立一个应用程序,首先出现在LogRocket博客上。