We take pride in our craft. As good software developers, we’ve learned all of the design patterns, and have adopted all of the industry’s best practices. We understand the importance of maintainable code that is resilient and can withstand failure conditions. And we would never think of deploying code that doesn’t adhere to these patterns and best practices, that is not at the pinnacle of resilience and maintainability.

我们以自己的Craft.io为荣。 作为优秀的软件开发人员,我们已经了解了所有设计模式,并采用了行业中的所有最佳实践。 我们了解具有可恢复性并且可以承受故障条件的可维护代码的重要性。 而且,我们永远也不会考虑部署不遵循这些模式和最佳实践的代码,而这并不是弹性和可维护性的顶峰。

Because good software developers don’t cut corners, right?

因为优秀的软件开发人员不会偷工减料,对吗?

Maybe so. But great ones sometimes do.

可能是吧。 但是有时候伟大的人也会这么做。

我们被雇用来解决问题,而不是磨练我们的手艺 (We’ve been hired to solve problems, not to hone our craft)

Unless we’re independently wealthy and are writing software as a hobby, someone is paying us. Not to produce the perfect design and to write pristine, impeccable code. But to solve problems. And often, those problems have budgets and timelines.

除非我们自己是有钱人并且以业余爱好来编写软件,否则有人会付钱给我们。 不能产生完美的设计并编写原始,无懈可击的代码。 但是要解决问题 。 通常,这些问题都有预算和时间表。

So that means that tradeoffs need to be made. While we might want to build a solution consisting of, say, a number of decoupled components communicating via events, with a robust retry and reconciliation framework… sometimes a single application talking to a database will need to suffice.

因此,这意味着需要进行权衡。 虽然我们可能想构建一个解决方案,例如,由多个通过事件进行通信的解耦组件组成,并具有健壮的重试和协调框架……有时与数据库通信的单个应用程序就足够了。

At the same time, there are reasons for the patterns that we want to follow, and for the coding standards to which we aspire. While a “quick and dirty” solution might work for now, it can lead to problems in the future.

同时,存在我们要遵循的模式以及我们追求的编码标准的原因。 尽管“快速而肮脏”的解决方案可能暂时适用,但将来可能会导致问题。

So what are we to do? On the one hand, we need to get our projects out, on time and on budget. On the other hand, we don’t want to set ourselves and our organization up for failure down the road.

那么我们该怎么办呢? 一方面,我们需要按时,按预算完成项目。 另一方面,我们不想让自己和我们的组织为将来的失败做好准备。

A quick story. Not too long ago, my son was involved in a walk-a-thon fundraiser. The premise was this: he and his classmates would walk around the block as many times as they could. Each lap would earn money for their school, as well as prizes for them.

一个简短的故事。 不久之前,我儿子参加了一次步行筹款活动。 前提是:他和他的同学会尽可能多地走在街区周围。 每圈将为他们的学校赚钱,并为他们赢得奖品。

Well, wouldn’t you know it. Towards the end of the event, I observed my son cutting a rather large corner, collecting prizes when he hadn’t technically completed the lap. I immediately pulled him aside and had a talk with him. The prizes had to be returned, I told him, unless he could fix the problem. So grudgingly, he returned to the starting spot and re-walked his incomplete lap.

好吧,你不知道吗。 在比赛快要结束时,我观察到我的儿子弯了一个大弯,在他还没有技术性地完成一圈时领奖。 我立即将他拉到一边,并与他交谈。 我告诉他,除非他能解决问题,否则必须退还奖金。 如此痛苦地,他回到了起点,重新走了他不完整的一圈。

When we cut corners in software, we will do the same thing. We’ll go back later and finish the job. And to be sure this happens, we’ll follow the following steps.

当我们在软件方面走捷径时,我们将做同样的事情。 我们待会儿再回去完成工作。 为确保这种情况发生,我们将遵循以下步骤。

除非确实存在问题,否则不要这样做 (Don’t do it unless there truly is a problem)

We shouldn’t cut corners just because we’re lazy. We should still aspire to all of the relevant patterns and best practices with anything that we’re producing.

我们不应该仅仅因为我们懒惰就偷工减料。 我们仍应追求我们正在生产的所有相关模式和最佳实践。

All too often, however, we run into this conundrum: we simply won’t be able to complete our project on time if we follow our optimal design. Something will need to give. Now, that “something” could be our timeline. Depending on the nature of our project, the norms of our organization, the temperament of our project manager, and a slew of other variables, we might ask for more time.

然而,很多时候,我们遇到了这个难题:如果遵循最佳设计,我们将无法按时完成项目。 需要付出一些。 现在,“事情” 可能成为我们的时间表。 根据项目的性质,组织的规范,项目经理的性情和其他变量,我们可能会要求更多时间。

Or we might not ask. Or… we might ask, but be turned down. At this point, indeed, corners will need to be cut.

否则我们可能不会问。 或者……我们可能会问,但是被拒绝了。 在这一点上,的确确实需要削减一些角落。

确定以后如何完成项目 (Determine how to later complete the project)

The first rule about cutting corners is that we won’t leave our corner in its cut state. Ultimately, we’ll need to finish our project as designed. So our next step is to determine how we’ll do that.

有关切角的第一个规则是,我们不会将角保持在切角状态。 最终,我们需要按设计完成项目。 因此,我们的下一步是确定我们将如何做。

In many cases, this may appear simple. If we intend to omit a certain component, then the fix will be to simply add that component. But we’ll need to make sure that it truly is that simple. Will we, for example, require any downtime to deploy the fix? Will we be able to properly test it before deploying it?

在许多情况下,这可能看起来很简单。 如果我们打算省略某个组件,那么解决方法是简单地添加该组件。 但是我们需要确保它真的就是这么简单。 例如,我们将需要任何停机时间来部署此修复程序吗? 在部署之前,我们是否能够对其进行适当的测试?

This leads directly into our next point…

这直接导致了我们的下一个观点……

如果以后无法(安全可行)修复它,请不要这样做 (Don’t do it if it can’t be (safely and feasibly) fixed later)

Once we’ve determined how we’ll finish the project, we need to determine how quick, and how safe, the fix will be. We don’t want to adversely affect later timelines, or introduce unreasonable amounts of risk, to un-cut our corner.

一旦确定了如何完成项目,就需要确定修复的速度和安全性。 我们不希望对以后的时间表产生不利影响,也不会引入不合理的风险,以消除我们的困境。

Certain types of fixes are going to be much quicker and safer than others. If we’re simply refactoring code within one application, then we can probably do that with minimal effort and risk. As our fix starts involving more than one component, our effort and risk starts expanding. Perhaps the most risky (and least feasible) fixes involve modifying data once it’s been persisted.

某些类型的修复将比其他修复更快,更安全。 如果我们只是在一个应用程序中重构代码,那么我们可以用最小的精力和风险来做到这一点。 随着我们的修复开始涉及多个组件,我们的努力和风险开始扩大。 最具风险(且最不可行)的修复程序可能涉及在数据持久化后对其进行修改。

As a simple example, we might be developing an application that saves and retrieves database data. Our typical design would call for a webapp to serve a UI, and a data microservice to persist the data. If we’re running up against a timeline, we might not have time to write both. In this case, we might choose to write only the web application, and temporarily allow it to read and write to/from the database schema. Later, we can add the data microservice.

举一个简单的例子,我们可能正在开发一个保存和检索数据库数据的应用程序。 我们的典型设计要求使用Web应用程序来提供UI,并使用数据微服务来持久化数据。 如果我们正在按照时间表运行,那么我们可能没有时间同时编写两者。 在这种情况下,我们可能选择只编写Web应用程序,并暂时允许它读写数据库模式。 稍后,我们可以添加数据微服务。

Assuming that the webapp will write to the same database that the microservice will later use, then our approach might be fine. However, if we’d need the webapp to write to some temporary data store, the contents of which would later need to be migrated to the data microservice’s new schema, then we might want to reconsider… and beg for more time to complete our project.

假设webapp将写入微服务以后使用的同一数据库,那么我们的方法可能很好。 但是,如果我们需要Web应用程序写入一些临时数据存储,然后将其内容稍后再迁移到数据微服务的新架构,那么我们可能要重新考虑……并乞求更多时间来完成我们的项目。

最小化回溯 (Minimize backtracking)

As we cut our corner, we might introduce a temporary solution that we will later jettison in favor of our preferred, permanent one. In other words, we will be doing “throw-away work.”

当我们走到尽头时,我们可能会提出一个临时解决方案,稍后我们将放弃我们的首选永久性解决方案。 换句话说,我们将进行“一次性工作”。

For example, we might determine that we’ll temporarily need to make direct HTTP calls between two services. Later, we will introduce asynchronous, event-based communication between the two. In this case, adding a POST endpoint to one service — and adding an HTTP client to the other — might be the quickest solution. But we’ll ultimately pull all of that code out. How much effort will we have spent on it?

例如,我们可能确定暂时需要在两个服务之间进行直接HTTP调用。 稍后,我们将介绍两者之间基于事件的异步通信。 在这种情况下,将POST端点添加到一项服务,并将HTTP客户端添加到另一项服务,可能是最快的解决方案。 但是,我们最终会将所有这些代码提取出来。 我们将为此付出多少努力?

Some amount of throw-away work will be acceptable. And if it’s required to get our project out on time, then so be it. But we should minimize the amount that we do.

可以进行一些一次性的工作。 如果需要按时完成我们的项目,那就这样吧。 但是,我们应该尽量减少所做的事情。

考虑一下与此同时我们将承受的任何其他风险 (Consider any added risk that we’ll be living with in the meantime)

Patterns and best-practices exist for a reason. So when we eschew them, we may be introducing some form of added risk, either short-term or long-term.

存在模式和最佳实践是有原因的。 因此,当我们避开它们时,我们可能会引入短期或长期的某种形式的附加风险。

In many cases, we’ll be cutting corners at the expense of future maintainability. If so, then as long as we will refactor and un-cut our corner soon after deploying it, then we can live with this risk.

在许多情况下,我们会偷工减料,以牺牲将来的可维护性为代价。 如果是这样,那么只要我们在部署它之后立即重构并消除困境,那么我们就可以承担这个风险。

In other cases, we might introduce some amount of immediate risk into our system. Let’s revisit our earlier example, where we’ve decided to temporarily eschew async, event-based communication with a direct HTTP call. This can lead to decreased resiliency if our downstream service is temporarily unavailable.

在其他情况下,我们可能会在系统中引入一些直接风险。 让我们重温之前的示例,在该示例中,我们决定暂时避免通过直接HTTP调用进行基于事件的异步通信。 如果我们的下游服务暂时不可用,这可能导致弹性降低。

So we will need to determine if this risk is acceptable.

因此,我们需要确定这种风险是否可以接受。

Sometimes, this will involve guesswork (what’s the likelihood that an HTTP call will fail?) Sometimes we will have data to back up our determination (what percentage of HTTP calls within out system have failed within the past month?) And more importantly, what is our tolerance for this risk?

有时,这会涉及猜测(HTTP调用失败的可能性是什么?)有时,我们将有数据来支持我们的判断(过去一个月内,系统内HTTP调用失败的百分比是多少?)更重要的是,什么我们对此风险的承受能力是什么?

不要决定自己做 (Don’t decide to do it on your own)

Once we’ve decided to cut some corners, we should immediately bring someone else in to the decision. At the very least, this should be another engineer on our team, one whose opinion we trust. Run the shortcut, along with the proposed solution, by them to see if it makes sense to them. Are there any risks we’ve overlooked? Are there better options?

一旦我们决定偷工减料,我们应该立即让其他人参与决策。 至少,这应该是我们团队中的另一位工程师,我们对此表示信任。 由他们运行快捷方式以及建议的解决方案,以查看是否对他们有意义。 有没有我们忽略的风险? 有更好的选择吗?

Since we’ll need to clean up our project after its intended completion date, then we’ll need buy-in from anyone who might object. Will our project manager be okay allocating time in the future to complete it? Does our director/CTO already have plans for us, post-project, that would preclude our ability to properly complete the project?

由于我们需要在计划的完成日期之后清理项目,因此我们需要任何可能反对的人的支持。 我们的项目经理会在将来分配时间来完成它吗? 项目负责人/首席技术官是否已经为我们制定了项目后计划,从而妨碍了我们正确完成项目的能力?

记录决策和后续修复 (Document the decision, and the subsequent fix)

Once we’ve determined that we will indeed cut that corner, and once we have determined how to fix it later, we’ll document it. We’ll note the specific reasons that this decision was consciously taken. Ideally, we’ll also note all of our co-workers who had agreed with the decision. We’ll identify any temporary risks that might be introduced. And of course, we’ll spell out how the shortcut will subsequently be fixed.

一旦确定确实可以解决这个问题,并且一旦确定以后如何修复,就将其记录在案。 我们将注意到有意识地做出此决定的具体原因。 理想情况下,我们还将注意所有同意该决定的同事。 我们将确定可能引入的任何临时风险。 当然,我们将阐明快捷方式随后将如何修复。

Where should we document all of this? It depends on our company’s process. If we typically create technical design docs (TDDs), then our project’s TDD would be a great place to document this. In addition, some team collaboration tools (like Confluence) offer decision templates, allowing us to easily document the decision.

我们应该在哪里记录所有这些? 这取决于我们公司的流程。 如果我们通常创建技术设计文档(TDD),那么我们项目的TDD将是记录此文档的好地方。 另外,一些团队协作工具(例如Confluence )提供了决策模板 ,使我们能够轻松地记录决策。

创建修复任务 (Create a task for the fix)

Even if we don’t formally document the task, we should absolutely file a task (e.g. a JIRA ticket, a Trello card, etc) for the solution. This reinforces our commitment to finishing up the project.

即使我们没有正式记录任务,也应该绝对提交解决方案的任务(例如JIRA票证, Trello卡等)。 这加强了我们完成项目的承诺。

确定任务的优先级,并确保完成任务 (Prioritize the task and make sure it gets done)

This is clearly the most important step of all. If we don’t actually complete our project properly, then all of our planning and best intentions will be for naught. And we and our company will be stuck with our cut corner, and all of the downsides carried with it.

这显然是最重要的一步。 如果我们实际上没有正确地完成我们的项目,那么我们所有的计划和最佳意图都是徒劳的。 而且我们和我们的公司将被困在我们的偷工减料中,所有不利之处也随之而来。

Of course, this might also be the most difficult step. Not only will we need to actually do the work, but we might find some resistance to the work being prioritized. Once a solution is out in production, and it basically works, folks tend to forget about best practices and start looking towards the next big project. In fact it might be tempting for us to forget about it.

当然,这也可能是最困难的步骤。 我们不仅需要实际进行工作,而且可能会对优先级较高的工作产生一些抵触。 一旦解决方案投入生产并基本 可行 ,人们往往会忘记最佳实践,而开始寻找下一个大型项目。 事实上,它可能是很有诱惑力让我们忘掉它。

We can’t let that happen. Even if it’s up to us — alone — to remind everyone of the importance of finishing the project properly, we’ll need to follow through.

我们不能让这种事情发生。 即使是我们自己一个人,也要提醒每个人正确完成项目的重要性,但我们仍需要遵循。

偷工减料:成功的故事 (Cutting Corners: a success story)

I had recently joined a company, and I had two primary focuses:

我最近加入了一家公司,主要关注两个方面:

  • Helping the engineering organization migrate from its monolith to microservices帮助工程组织从其整体迁移到微服务
  • Leading some of the company’s vertical product teams领导公司的一些垂直产品团队

One of my teams’ first major initiatives involved bringing the native mobile apps up to par with the main website. I saw this as a perfect opportunity to marry product development with building out microservices. Up until that point, the mobile apps had simply communicated with a legacy, monolithic backend application. This would be our opportunity to start building out a set of services that our mobile apps could use.

我团队的第一个主要举措之一是使本地移动应用程序与主要网站保持一致。 我认为这是将产品开发与构建微服务结合起来的绝佳机会。 到那时为止,移动应用程序仅与旧的整体式后端应用程序进行了通信。 这将是我们开始构建移动应用程序可以使用的一组服务的机会。

Our proposed design looked roughly like this:

我们提出的设计大致如下所示:

Our initial pattern was to build individual data services that still read/wrote data from/to our existing monolithic database. We would worry about migrating data to new, individual schemas later.
我们最初的模式是建立单独的数据服务,该服务仍可从现有的整体数据库中读取/写入数据。 我们将担心稍后将数据迁移到新的单个架构。

The mobile app would send a request to the Orchestration Service. In turn, the Orchestration Service would make a call to Data Service A. Depending on the results of that call, the orchestration service would make subsequent calls to Data Service B or Data Service C (or both). The response would then be packaged up in a format optimized for the mobile app, and returned.

移动应用程序将向Orchestration Service发送请求。 反过来, 业务流程服务将调用数据服务A。 根据该调用的结果,编排服务将随后对数据服务B数据服务C (或两者)进行调用。 然后,响应将以针对移动应用优化的格式打包并返回。

The problem was that at this point, Data Service B and Data Service C did not yet exist. No problem, I thought, then team can create them. Unfortunately, the project had been scoped according to the old timelines, when feature development meant simply adding more code to the monolith. We clearly would not be able to hit the project’s deadline while still building out the new services.

问题在于,此时, 数据服务B数据服务C尚不存在。 我认为没问题然后团队可以创建它们 。 不幸的是,该项目是根据旧的时间表来确定范围的,当时功能开发意味着仅向整体添加更多代码。 我们显然仍无法按时完成项目,同时仍在构建新服务。

My first proposal was that we push out the timeline. After talking with the team’s project manager, I learned that timelines were, currently, being heavily scrutinized. Moreover, I realized that if we were to maintain company support for the microservices endeavor, we should first demonstrate our ability to meet timelines.

我的第一个建议是我们推迟时间表。 与团队的项目经理交谈后,我了解到目前正在认真审查时间表。 此外,我意识到,如果我们要保持公司对微服务事业的支持,那么我们首先应该证明我们有能力按时完成任务。

So pushing the timeline was not a good option. Yet, we could not afford to attach such a major piece of functionality to the old monolith. So I sketched out a solution. The Orchestration Service would temporarily make direct calls to the database, in lieu of services B and C. Once the project was released and working in production, the team would build those two services, and redirect the Orchestration Service to call them instead.

因此,推迟时间表并不是一个好的选择。 但是,我们不能将如此重要的功能附加到旧的整体上。 所以我草拟了一个解决方案。 Orchestration Service将代替服务BC临时直接调用数据库。 项目发布并投入生产后,团队将构建这两个服务,并重定向业务流程服务以代替调用它们。

We would need to temporarily introduce a database driver, and data access code, to the Orchestration Service — we would subsequently remove it all because, ideally, an orchestration service should not be talking to a database. That meant some throwaway work, but not too much.

我们将需要向Orchestration Service临时引入数据库驱动程序和数据访问代码-我们随后将其全部删除,因为理想情况下,业务流程服务不应与数据库进行通信。 这意味着需要做一些一次性的工作,但不要太多。

We could easily deploy and monitor services B and C independently. Once they were running in production, we would release the updated Orchestration Service.

我们可以轻松地独立部署和监视服务BC。 他们投入生产后,我们将发布更新的Orchestration Service

I ran the idea past one of my peers (who was also involved in the microservices architecture, and was similarly managing vertical teams of his own.) He agreed with the approach, and between the two of us, we could not identify any major risks. So I wrote up the proposal in Confluence, and got my project manager’s buy-in. I then created a JIRA ticket, slated to be prioritized for the following sprint.

我将这个想法发给了我的一位同事(他也参与了微服务体系结构,并且类似地管理着他自己的垂直团队。)他同意这种方法,并且在我们两个人之间,我们无法确定任何重大风险。 因此,我在Confluence中编写了提案,并得到了项目经理的支持。 然后,我创建了JIRA票证,该票证将优先用于下一个冲刺。

The result? A project completed on time, demonstrating the ability for our mobile apps to rely on microservices rather than our monolith. And in the following sprint, we finished up the project by building and deploying the missing microservices.

结果? 一个按时完成的项目证明了我们的移动应用依靠微服务而不是整体服务的能力。 在接下来的sprint中,我们通过构建和部署缺少的微服务来完成项目。

最终剪辑 (The final cut)

Cutting corners is never ideal. But we need to be willing to do it when necessary. Moreover, we should be thoughtful in our approach, and follow these basic steps:

偷工减料从来都不是理想的。 但是我们需要在必要时愿意这样做。 此外,我们应该谨慎考虑方法,并遵循以下基本步骤:

  • Be sure it’s truly necessary确保确实有必要
  • Consider — and try to minimize — any added risk考虑(并尽量减少)任何附加风险
  • Minimize throw-away work尽量减少一次性工作
  • Get a second (and third, and fourth…) opinion获得第二(第三和第四…)意见
  • Most importantly: develop a plan to subsequently, properly complete the project… and be sure that the plan is followed through!最重要的是:制定一个计划,以随后正确地完成该项目……并确保遵循该计划!

翻译自: https://levelup.gitconnected.com/how-to-cut-corners-when-writing-software-d151cb0af5d9


http://www.taodudu.cc/news/show-2901141.html

相关文章:

  • 领域分类的问题_别人的问题领域
  • 永远不要忘记_它永远不会忘记一张脸
  • 永磁电机极对数一般是多少_对数是多少
  • ubuntu20.04如何录制屏幕
  • 桌面视频录制
  • 桌面应用程序脚本录制
  • FFmpeg —— 录制Windows桌面与麦克风,音视频同步(附源码)
  • ffmpeg Windows下录制桌面视频命令
  • electron实现屏幕录制
  • 桌面计算机1008桌面计算机,windows桌面精灵
  • FFMPEG音视频开发: 完成摄像头、桌面本地录制与rtmp推流(windows)
  • 桌面录制软件
  • FFmpeg 录制桌面、麦克风、摄像头
  • Android录制桌面视频screenrecord
  • python实现屏幕视频录制_用Python来做一个屏幕录制工具
  • kazam使用_尝试使用2种免费的桌面录制工具:SimpleScreenRecorder和Kazam
  • windows、mac桌面录制GIF
  • ffmpeg录制桌面视频和系统内部声音(音视频同步)
  • 桌面录制gif图像
  • ffmpeg录制桌面(自己用gdi抓图)
  • 电脑桌面录制直播嵌入网页
  • QuickTime的桌面录制
  • 3dmaxs坐标轴不显示灰色显示(没有坐标轴箭头)
  • Photoshop的时间轴是灰色的,不能使的解决方法
  • 倍福--NC轴无法使能分析
  • 解决premiere时间轴clip单元上右键Edit in audition编辑灰色失效的BUG
  • 什么轴的机械键盘声音小
  • Tableau实用小技巧之——双轴图表设置同步轴
  • 灰色系统预测模型GM(1,1),GM(1,n)及Matlab实现
  • ggplot2设置坐标轴范围_ggplot2|详解八大基本绘图要素

编写软件时如何偷工减料相关推荐

  1. 代码编写工具_我希望在开始编写代码时就已经知道的工具:已复习

    代码编写工具 by Mario Hoyos 通过马里奥·霍约斯(Mario Hoyos) 我希望在开始编写代码时就已经知道的工具:已复习 (Tools I wish I had known about ...

  2. vb.net编写函数应该在哪里_编写代码时清晰至上

    好的代码是清晰的代码,而不是聪明的代码 Photo by David Travis on Unsplash 许多程序员尝试编写干净,智能的代码. 但是,有时候,痴迷于智能可能会使代码库更难以理解,并且 ...

  3. 产品研发过程管理专题——编写软件测试计划需要考虑的几个问题

    软件测试是有计划.有组织和有系统的软件质量保证活动,而不是随意地.松散地.杂乱地实施过程.为了规范软件测试内容.方法和过程,在对软件进行测试之前,必须创建测试计划. <ANSI/IEEE软件测试 ...

  4. Guitar Pro8吉他谱编写软件下载安装及使用教程

    音乐制作的许多程序都可以借助软件来完成,吉他谱的编写也是如此.今天要和大家分享的是吉他谱编写软件Guitar Pro,吉他谱怎么做电子版. 提到吉他谱的编写,有一款软件总是被第一时间想到,那就是Gui ...

  5. 软件工程流程图编写软件_如何编写杀手级软件工程简历

    软件工程流程图编写软件 对简历的深入分析使我在Google,Facebook,亚马逊,微软,苹果等公司接受了采访. (An in-depth analysis of the résumé that g ...

  6. java培训教程分享:Java编写软件代码自动提示功能

    本期的java培训教程分享主要是介绍的java编写软件代码的一个自动提示功能,很多零基础和初学java的同学们对这一块还不是很了解,Eclipse for android 实现代码自动提示智能提示功能 ...

  7. Linux安装软件时缺少依赖包的简单较完美解决方法!

    Linux安装软件时缺少依赖包的简单较完美解决方法! 参考文章: (1)Linux安装软件时缺少依赖包的简单较完美解决方法! (2)https://www.cnblogs.com/xiaommvik/ ...

  8. mysql编写中文时变成问号解决方法

    mysql编写中文时变成问号解决方法 参考文章: (1)mysql编写中文时变成问号解决方法 (2)https://www.cnblogs.com/yangzhixue/p/11449525.html ...

  9. idea修改java和jsp不起作用_使用IDEA编写jsp时EL表达式不起作用的问题及解决方法...

    在使用IDEA开发maven+springMVC项目时遇到不加载EL表达式的问题,怎么处理呢?下面小编给大家带来了实现代码,一起看看吧 加载如下JSP代码: Title ${lists.usernam ...

最新文章

  1. Thrall’s Dream HRBUST - 2048【BFS or 强连通分量】
  2. QD75运动模块使用
  3. Android之android studio如何获取证书指纹 (SHA1)
  4. K - Let the Flames Begin
  5. Win32ASM-进程学习[3]-读写进程空间
  6. 大数据之-Hadoop3.x_MapReduce工作流程---大数据之hadoop3.x工作笔记0109
  7. 开源风云 20 年!
  8. lua如何判断是否支持cookie_如何判断面部是否需要吸脂
  9. 机器学习基础算法27-聚类实战
  10. 物联网来了,智能城市离我们还有多远?
  11. 100道最新Java面试题,常见面试题及答案汇总
  12. 会计实务综合模拟计算机实训心得,模拟企业会计实训心得体会
  13. 去除html中的font标签的正则表达式
  14. python客户端_python客户端编程
  15. 记录自定义维护视图的修改日志
  16. uniapp ios打包详细步骤
  17. batchnorm原理及代码详解
  18. vue3+vant开发微信公众号网页爬坑不完全指北
  19. python爬虫 - 代理ip正确使用方法
  20. python的图片转PDF

热门文章

  1. 浅析大规模DDOS防御架构-应对T级攻防
  2. php逐个汉字遍历字符串
  3. 多项式(带余)除法学习笔记
  4. DOTA2攻速计算公式研究
  5. 分布式存储系统——《Neo4j》
  6. 西电计组实验一 存储器实验
  7. 6月小红书博主排行,谁是最佳创作者?
  8. 下载erlang的.rpm文件 erlang下载 centos安装rabbitmq
  9. 用命令操作方式创建和管理数据库
  10. 会员营销中,沉寂会员的三种运营策略