Home Development of Websites The Good, the Bad and the Ugly code

The Good, the Bad and the Ugly code

by admin

The Good, the Bad and the Ugly code
Good code or bad code? For me personally, good code has the following qualities :

  • The code is easily understood by developers of different skill sets and is well structured
  • The code is easy to modify and maintain
  • The application performs its functions and has sufficient, for the range of tasks, fault tolerance

Despite the short description, many thick books have been written on how to achieve these three conditions.
Why these criteria? Let me say right away that we are talking about software development for business (enterprise application) Code evaluation criteria are different for real-time systems, aircraft, life support systems, and the ISS.
The Good, the Bad and the Ugly code
Surely everyone, or almost everyone, is familiar with this triangle.
Of the three conditions – fast, high quality, cheap – only two can be met at the same time.
When developing business applications, our goal is to develop good enough software in a reasonable time, staying within budget.In practice, this means that there may be bugs in our application, but in places that are not critical to the system.Let’s look at a few examples to get a better understanding of what this means.

Case #1

The form has a text input field (textarea). You can enter 100500 characters into it and our application will crash with exception "query length exceeded".
Is this our case study? Hardly. If it’s a public part, you should put a java-script validator and not let you post forms like this. Configuring the server somehow additionally for those who have disabled java-script is just a waste of time, and therefore budget. We are not going to do that. Yes, there is a potential bug in our application. Does anyone need to have it fixed? No.

Case No. 2

A request comes in from the client: we need an affiliate page. This page will have brief information about each of them and a link to the page where we need to embed an iframe page from the partner’s site.
Interesting case study. I guess we need to make a change to the database, add a partner entity, db-entity by design we don’t pass to View, so we need more DTO, mapping function from db-entity to dto, more database migration for auto-deploy. Hmmm, also need a page in admin to add a partner. Don’t forget the routing for the controller so it’s /Partner/<PARTNER_NAME> Quite a lot of work…
True for 10, 000 partners. Let’s inquire : "how many partners there will be." ? If the answer is "this year three." We should reconsider. This is again a time and budget overrun. Only three partners?
The Good, the Bad and the Ugly code

namespace Habrahabr.Models.Partner{public class PartnerViewModel{public string Name { get; set; }public string WebSiteUrl { get; set; }public string ShortDescription { get; set; }public string FullDescription { get; set; }}}using System.Web.Mvc;using Habrahabr.Models.Partner;namespace Habrahabr.Controllers{public class PartnerController : Controller{private static PartnerViewModel[] partners = new[]{new PartnerViewModel(){Name = "Coca-Cola", WebSiteUrl = "http://coca-cola.com/partner", ShortDescription = "Coca-cola short description", FullDescription = "Coca-cola full description"}, new PartnerViewModel(){Name = "Ikea", WebSiteUrl = "http://ikea.com/partner", ShortDescription = "Ikea short description", FullDescription = "Ikea full description"}, new PartnerViewModel(){Name = "Yandex", WebSiteUrl = "http://yandex.ru/partner", ShortDescription = "Yandex short description", FullDescription = "Yandex full description"}};public ActionResult Index(){// TODO: populate partners from database if a lot of partner requiredreturn View(partners);}// TODO: refactor this if a lot of partner required[ActionName("Coca-Cola")]public ActionResult CocaCola(){return View("_PartnerDetail", partners[0]);}public ActionResult Ikea(){return View("_PartnerDetail", partners[1]);}public ActionResult Yandex(){return View("_PartnerDetail", partners[2]);}}}@model IEnumerable<Habrahabr.Models.Partner.PartnerViewModel><ul>@foreach (var p in @Model){<li><h3> @Html.ActionLink(p.Name, p.Name, "Partner")</h3><div> @p.ShortDescription</div><p class="info"> @Html.ActionLink("Partnerpage", p.Name, "Partner")</p></li>}</ul>@model Habrahabr.Models.Partner.PartnerViewModel<h2> @Model.Name</h2><div> @Model.FullDescription</div>@if (!string.IsNullOrEmpty(Model.WebSiteUrl)){<iframe width="100%" height="500" src="@Model.WebSiteUrl"> </iframe>}

The Good, the Bad and the Ugly code
The Good, the Bad and the Ugly code
All in all, it takes an hour at most, including text entry. We have developed a pretty good affiliate page. Does it meet our criteria :

  • Clear and structured – yes
  • Easily changeable – yes
  • Reliable enough – yes

Subject matter, data access, and application architecture

Fowler correctly notes in his book Enterprise Patterns of Enterprise Application Architecture that the term "architecture" is incredibly vague :

Everyone tries to interpret the term "architecture" in his or her own way. But we can give you two general variants. The first one is associated with the division of the system into its largest constituent parts; in the second case, it refers to some constructive solutions, which, once adopted, are difficult to change. There is also a growing awareness that there is more than one way to describe the architecture and the degree of importance of each varies as the system lifecycle continues.

The partner approach described above has one significant limitation. You can’t write application code in this style all the time. Sooner or later the system will grow. In this case, we have "sewn" the logic of the application. A couple more of these controllers and it will be quite difficult to understand how the system works, especially for new developers.
The moment we find out that there will be not 3 but 100500 partners and we should not show all of them, but only the ones who paid on Friday night (from 13th to 14th) and sacrificed 6 virgins and the pages should be rotated according to the Venus and Jupiter positions (in real life cases are of course different, but they say that there is nothing more illogical for developer than "business logic", consisting only of exceptions and special cases). We need to think about architecture in both senses of the word.
We have left the "stitches" in the appendix ahead of time, and we will begin to unstitch them and sew the necessary pieces on. We will use ORM , we’ll rename PartnerViewModel in Partner and mask the partner class in the database. I have never used Database-First and didn’t take seriously Entity Framework until a version came out with Code-First approach. In this case, I don’t see the need to map Partner in PartnerViewModel Yes, semantically these entities perform different tasks and in general PartnerViewModel may be different, but so far there’s not a single reason to write exactly the same class. Mapit ViewModel makes sense when you can’t do without it without dragging logic into the view. Usually the need for the ViewModels. appears if you need to show a complex form in the interface that operates with several entities of the same subject area, or if you need to use the attributes from the System.Web for model properties. In the latter case, I tend to drag this dependency into the subject area assembly if I’m sure there won’t be a new entry point in the application in the next six months other than the main web application.
In one project I was involved in, in order to access the data, it was necessary to call a service that accessed the facade, which in turn accessed DALlayer which invoked the Entity Framework Facade and DAL were in different assemblies, and EF used the approach of Database-First All the logic was usually done by DAL and the other layers simply re-mapped the results 90% of the time into an absolutely identical DTO The system had no other clients and objectively didn’t need the service. When I asked "why such an overhead", the developer, who had been working on the project longer, said: "I don’t know, our other project was written that way, we decided to make it by analogy". Yes, this "other project" consisted of 20 applications and it took 2 days just to deploy it. The API of that application has many clients. Such a complex structure was a necessity. In our case it was firing a cannon at sparrows.
But back to our sheep partners. It remains to understand where to write the code responsible for selecting the necessary partners for display. As a reminder, we must now consider Venus and Jupiter. The worst place is the controller. By doing this we will scatter the logic of the application over different parts of it and new developers will have to assemble it (the logic), like Harry Potter assembling Horcruxes
A good option is to use the pattern repository specification

IOC/DI

As the application grows, there is a danger of making it too strongly coupled, and this will make the system clumsy and interfere with code changes.
I won’t describe once again what IOC/DIis and what it’s about, you just have to take it as a rule:

  • Do not create dependencies explicitly
  • Use IOC containers

You don’t have to create an interface for every class in the project. It is often easier to isolate the interface later. R# handles this very well. But keep this in mind when you write a class. Think of it as an interface, not as a specific implementation. Using DI you can flexibly manage implementations. If necessary, you can drop one implementation and replace it with another, for example, if for some reason the database stops working for you, you can transparently replace it by replacing the repository implementation. Other than that, using IOC/DI is much easier to write testable code.

Tests

I’m not a fan of 90-100% project coverage. I think, more often than not, it slows down development and makes code maintenance a much more torturous task. I prefer to cover system behavior, i.e. the basic business rules of the application, with tests. This way tests not only insure against bugs but also help new developers understand the system logic faster. Such tests work better than any documentation. Tests using BDD notation are especially effective.

Further development of the system

If the application continues to grow, it is difficult to give specific advice : too many factors to consider. Too much depends on the specifics of the project. A good solution might be SOA In general, decomposing any large system is a great idea. Ten projects loaded in your IDE or a hundred – the difference is very big. When developing software of this scale you can’t do without deploy scripts, installers and release management, but that’s a whole other story…

Lambda, Aspects, Functionality, and Other Choline

As a final note, I thought I’d leave some points of contention. I’ve noticed that many developers tend to "get used" to the stack they work with. If a programmer is "used to" his stack, he tends to drag it into every new project, regardless of expediency. Thus, I’ve heard C# criticized many times for "flirting" with functional style, lambdas that compile into "who-knows-what" and "don’t debug" and other extension-methods. Objectively, we see that in php added closures, in java8 will appear Stream for streaming collections, which means a lot of developers will like it.
Don’t be afraid to combine paradigms if it’s worth it. Ask yourself the questions "how much platform/language/OS is right for the task?" and "what technology will help me accomplish the task as efficiently as possible?" My point is best illustrated by the quote iliakan :

I figured it would be faster to learn Erlang or make Java work fast enough so I decided to learn Erlang

Books on the topic

You may also like