Programming

한때 마음에 들었던 프로그래밍 관행에 대해 마음이 바뀌 었습니까?

procodes 2020. 8. 19. 20:14
반응형

한때 마음에 들었던 프로그래밍 관행에 대해 마음이 바뀌 었습니까? [닫은]


프로그래밍 할 때 우리 모두는 우리가 사용하고 의존하는 관행과 패턴을 개발합니다. 그러나 시간이 지남에 따라 우리의 이해, 성숙도, 심지어 기술 사용이 변경됨에 따라 우리는 한때 훌륭하다고 생각했던 일부 관행이 그렇지 않거나 더 이상 적용되지 않는다는 것을 깨닫게됩니다.

한때 자주 사용했지만 최근 몇 년 동안 변경된 사례는 Singleton 객체 패턴을 사용하는 것입니다 .

내 자신의 경험과 동료들과의 긴 토론을 통해 싱글 톤이 항상 바람직한 것은 아니라는 것을 깨달았습니다. 싱글 톤은 테스트를 더 어렵게 만들 수 있고 (모킹과 같은 기술을 억제함으로써) 시스템 부분 사이에 바람직하지 않은 결합을 만들 수 있습니다. 대신, 이제는 신경 쓰지 않거나 알 필요가없는 시스템 부분에서 싱글 톤의 특성과 존재를 숨기는 객체 팩토리 (일반적으로 IoC 컨테이너 사용)를 사용합니다. 대신, 이러한 개체에 대한 액세스 권한을 얻기 위해 공장 (또는 서비스 로케이터)에 의존합니다.

자기 계발 정신으로 커뮤니티에 대한 나의 질문은 다음과 같습니다.

  • 최근에 어떤 프로그래밍 패턴이나 관행을 재고하고 이제 피하려고하십니까?
  • 무엇으로 교체하기로 결정 했습니까?


//Coming out of university, we were taught to ensure we always had an abundance 
//of commenting around our code. But applying that to the real world, made it 
//clear that over-commenting not only has the potential to confuse/complicate 
//things but can make the code hard to follow. Now I spend more time on 
//improving the simplicity and readability of the code and inserting fewer yet 
//relevant comments, instead of spending that time writing overly-descriptive 
//commentaries all throughout the code.



단일 리턴 포인트.

나는 루틴에 필요한 정리가 간과되지 않도록 보장 할 수 있었기 때문에 각 메소드에 대해 단일 리턴 포인트를 선호했습니다.

그 이후로 저는 훨씬 더 작은 루틴으로 이동했습니다. 따라서 정리를 간과 할 가능성이 줄어들고 실제로 정리 필요성 이 줄어 듭니다. 그리고 조기 반환이 코드의 명백한 복잡성 (중첩 수준)을 감소 시킨다는 것을 알게되었습니다. 단일 반환점의 아티팩트 ( "결과"변수 유지, 플래그 변수 유지, 아직 완료되지 않은 상황에 대한 조건절 유지)는 코드가 실제보다 훨씬 더 복잡해 보이게하고 읽기 및 유지 관리를 어렵게 만듭니다. 초기 출구와 더 작은 방법이 갈 길이다.


  • 첫 번째 시도에서 완벽하게 코딩하려고합니다.
  • 코딩하기 전에 완벽한 OO 모델을 만들려고합니다.
  • 유연성과 향후 개선을 위해 모든 것을 설계합니다.

한마디로 오버 엔지니어링 .


헝가리 표기법 (양식 및 시스템 모두). 나는 모든 것을 접두사로 사용했습니다. strSomeString 또는 txtFoo. 이제 someString 및 textBoxFoo를 사용합니다. 새로운 누군가가 와서 픽업하기가 훨씬 더 읽기 쉽고 쉽습니다. 추가 보너스로 일관성을 유지하는 것은 사소한 일입니다. 컨트롤을 camelCase하고 유용하고 설명적인 이름을 추가합니다. Forms Hungarian은 항상 일관성이 없다는 단점이 있으며 Systems Hungarian은 실제로 많은 것을 얻지 못합니다. 모든 변수를 함께 묶는 것은 특히 최신 IDE의 경우 그다지 유용하지 않습니다.


"완벽한"아키텍처

저는 몇 년 전에 THE 아키텍처를 생각해 냈습니다 . 100 % 느슨하게 결합 된 레이어, 광범위한 델리게이트 사용, 경량 오브젝트가되도록 기술적으로 최대한 밀어 붙였습니다. 기술의 천국이었습니다.

그리고 그것은 쓰레기였습니다. 아키텍처의 기술적 순수성은 결과에 대한 완벽 함을 목표로 개발 팀의 속도를 늦추고 거의 완전한 실패를 달성했습니다.

이제 기술적으로 완벽하지 않은 아키텍처가 훨씬 단순 해졌고 제공 속도가 급증했습니다.


카페인 사용. 그것은 한때 나를 깨우고 영광스러운 프로그래밍 분위기로 유지했습니다. 코드가 열광적 인 유동성으로 내 손가락에서 날아갔습니다. 이제는 아무 일도하지 않으며, 없으면 두통이 생깁니다.


코드 주석 처리. 나는 코드가 소중하고 자신이 만든 아름다운 보석을 삭제할 수 없다고 생각했습니다. 이제는 주석 처리 된 코드를 삭제합니다. 주석 처리 된 코드는 그대로두기에는 너무 위험하기 때문에 첨부 된 TODO 또는 NOTE가없는 경우 삭제됩니다. 재치로, 주석 처리 된 부분이 많은 오래된 클래스를 보았습니다. 거기에 있었습니까 : 그들은 최근에 주석을 달았습니까? 이것은 개발 환경 변경입니까? 이 무관 한 차단을하는 이유는 무엇입니까?

코드를 주석 처리하지 않고 대신 삭제하는 것을 진지하게 고려하십시오. 필요한 경우 여전히 소스 제어에 있습니다. 그래도 YAGNI.


#region 지시문의 남용 / 남용. 사소한 일이지만 C #에서는 이전에 클래스를 구성하기 위해 #region 지시문을 모든 곳에서 사용했습니다. 예를 들어 모든 클래스 속성을 한 지역에 함께 그룹화합니다.

이제 나는 오래된 코드를 되돌아보고 대부분 그저 짜증이납니다. 나는 그것이 정말로 대부분의 경우 일을 더 명확하게 해주지 않는다고 생각하며 때때로 그들은 당신을 느리게 만듭니다. 그래서 나는 이제 마음을 바꾸었고 잘 짜여진 클래스가 지역 지시 없이 대부분 깨끗하다고 ​​느낍니다 .


일반적으로 폭포 개발, 구체적으로는 완전하고 포괄적 인 기능 및 디자인 사양을 작성하는 관행으로, 어떻게 든 정식이 될 것으로 예상되고 그 구현이 정확하고 수용 가능할 것으로 기대합니다. 나는 그것이 스크럼으로 대체되는 것을 보았습니다. 단순한 사실은 고객의 요구와 욕구의 변화하는 특성으로 인해 고정 된 사양을 효과적으로 쓸모 없게 만든다는 것입니다. 문제에 제대로 접근하는 유일한 방법은 반복적 인 접근 방식입니다. 물론 스크럼이 은색 총알은 아닙니다. 나는 그것이 오용되고 남용되는 것을 여러 번 보았다. 그러나 그것은 폭포를 이깁니다.


충돌하지 않습니다.

It seems like such a good idea, doesn't it? Users don't like programs that crash, so let's write programs that don't crash, and users should like the program, right? That's how I started out.

Nowadays, I'm more inclined to think that if it doesn't work, it shouldn't pretend it's working. Fail as soon as you can, with a good error message. If you don't, your program is going to crash even harder just a few instructions later, but with some nondescript null-pointer error that'll take you an hour to debug.

My favorite "don't crash" pattern is this:

public User readUserFromDb(int id){
    User u = null;
    try {
        ResultSet rs = connection.execute("SELECT * FROM user WHERE id = " + id);
        if (rs.moveNext()){
            u = new User();
            u.setFirstName(rs.get("fname"));
            u.setSurname(rs.get("sname"));
            // etc
        }
    } catch (Exception e) {
        log.info(e);
    }
    if (u == null){
        u = new User();
        u.setFirstName("error communicating with database");
        u.setSurname("error communicating with database");
        // etc
    }
    u.setId(id);
    return u;
}

Now, instead of asking your users to copy/paste the error message and sending it to you, you'll have to dive into the logs trying to find the log entry. (And since they entered an invalid user ID, there'll be no log entry.)


I thought it made sense to apply design patterns whenever I recognised them.

Little did I know that I was actually copying styles from foreign programming languages, while the language I was working with allowed for far more elegant or easier solutions.

Using multiple (very) different languages opened my eyes and made me realise that I don't have to mis-apply other people's solutions to problems that aren't mine. Now I shudder when I see the factory pattern applied in a language like Ruby.


Obsessive testing. I used to be a rabid proponent of test-first development. For some projects it makes a lot of sense, but I've come to realize that it is not only unfeasible, but rather detrimental to many projects to slavishly adhere to a doctrine of writing unit tests for every single piece of functionality.

Really, slavishly adhering to anything can be detrimental.


This is a small thing, but: Caring about where the braces go (on the same line or next line?), suggested maximum line lengths of code, naming conventions for variables, and other elements of style. I've found that everyone seems to care more about this than I do, so I just go with the flow of whoever I'm working with nowadays.

Edit: The exception to this being, of course, when I'm the one who cares the most (or is the one in a position to set the style for a group). In that case, I do what I want!

(Note that this is not the same as having no consistent style. I think a consistent style in a codebase is very important for readability.)


Perhaps the most important "programming practice" I have since changed my mind about, is the idea that my code is better than everyone else's. This is common for programmers (especially newbies).


Utility libraries. I used to carry around an assembly with a variety of helper methods and classes with the theory that I could use them somewhere else someday.

In reality, I just created a huge namespace with a lot of poorly organized bits of functionality.

Now, I just leave them in the project I created them in. In all probability I'm not going to need it, and if I do, I can always refactor them into something reusable later. Sometimes I will flag them with a //TODO for possible extraction into a common assembly.


Designing more than I coded. After a while, it turns into analysis paralysis.


The use of a DataSet to perform business logic. This binds the code too tightly to the database, also the DataSet is usually created from SQL which makes things even more fragile. If the SQL or the Database changes it tends to trickle to everything the DataSet touches.

Performing any business logic inside an object constructor. With inheritance and the ability to create overloaded constructors tend to make maintenance difficult.


Abbreviating variable/method/table/... Names

I used to do this all of the time, even when working in languages with no enforced limits on lengths of names (well they were probably 255 or something). One of the side-effects were a lot of comments littered throughout the code explaining the (non-standard) abbreviations. And of course, if the names were changed for any reason...

Now I much prefer to call things what they really are, with good descriptive names. including standard abbreviations only. No need to include useless comments, and the code is far more readable and understandable.


Wrapping existing Data Access components, like the Enterprise Library, with a custom layer of helper methods.

  • It doesn't make anybody's life easier
  • Its more code that can have bugs in it
  • A lot of people know how to use the EntLib data access components. No one but the local team knows how to use the in house data access solution

I first heard about object-oriented programming while reading about Smalltalk in 1984, but I didn't have access to an o-o language until I used the cfront C++ compiler in 1992. I finally got to use Smalltalk in 1995. I had eagerly anticipated o-o technology, and bought into the idea that it would save software development.

Now, I just see o-o as one technique that has some advantages, but it's just one tool in the toolbox. I do most of my work in Python, and I often write standalone functions that are not class members, and I often collect groups of data in tuples or lists where in the past I would have created a class. I still create classes when the data structure is complicated, or I need behavior associated with the data, but I tend to resist it.

I'm actually interested in doing some work in Clojure when I get the time, which doesn't provide o-o facilities, although it can use Java objects if I understand correctly. I'm not ready to say anything like o-o is dead, but personally I'm not the fan I used to be.


In C#, using _notation for private members. I now think it's ugly.

I then changed to this.notation for private members, but found I was inconsistent in using it, so I dropped that too.


I stopped going by the university recommended method of design before implementation. Working in a chaotic and complex system has forced me to change attitude.

Of course I still do code research, especially when I'm about to touch code I've never touched before, but normally I try to focus on as small implementations as possible to get something going first. This is the primary goal. Then gradually refine the logic and let the design just appear by itself. Programming is an iterative process and works very well with an agile approach and with lots of refactoring.

The code will not look at all what you first thought it would look like. Happens every time :)


I used to be big into design-by-contract. This meant putting a lot of error checking at the beginning of all my functions. Contracts are still important, from the perspective of separation of concerns, but rather than try to enforce what my code shouldn't do, I try to use unit tests to verify what it does do.


I would use static's in a lot of methods/classes as it was more concise. When I started writing tests that practice changed very quickly.


Checked Exceptions

An amazing idea on paper - defines the contract clearly, no room for mistake or forgetting to check for some exception condition. I was sold when I first heard about it.

Of course, it turned to be such a mess in practice. To the point of having libraries today like Spring JDBC, which has hiding legacy checked exceptions as one of its main features.


That anything worthwhile was only coded in one particular language. In my case I believed that C was the best language ever and I never had any reason to code anything in any other language... ever.

I have since come to appreciate many different languages and the benefits/functionality they offer. If I want to code something small - quickly - I would use Python. If I want to work on a large project I would code in C++ or C#. If I want to develop a brain tumour I would code in Perl.


When I needed to do some refactoring, I thought it was faster and cleaner to start straightaway and implement the new design, fixing up the connections until they work. Then I realized it's better to do a series of small refactorings to slowly but reliably progress towards the new design.


Perhaps the biggest thing that has changed in my coding practices, as well as in others, is the acceptance of outside classes and libraries downloaded from the internet as the basis for behaviors and functionality in applications. In school at the time I attended college we were encouraged to figure out how to make things better via our own code and rely upon the language to solve our problems. With the advances in all aspects of user interface and service/data consumption this is no longer a realistic notion.

There are certain things which will never change in a language, and having a library that wraps this code in a simpler transaction and in fewer lines of code that I have to write is a blessing. Connecting to a database will always be the same. Selecting an element within the DOM will not change. Sending an email via a server-side script will never change. Having to write this time and again wastes time that I could be using to improve my core logic in the application.


Initializing all class members.

I used to explicitly initialize every class member with something, usually NULL. I have come to realize that this:

  • normally means that every variable is initialized twice before ever being read
  • is silly because in most languages automatically initialize variables to NULL.
  • actually enforces a slight performance hit in most languages
  • can bloat code on larger projects

Like you, I also have embraced IoC patterns in reducing coupling between various components of my apps. It makes maintenance and parts-swapping much simpler, as long as I can keep each component as independent as possible. I'm also utilizing more object-relational frameworks such as NHibernate to simplify database management chores.

In a nutshell, I'm using "mini" frameworks to aid in building software more quickly and efficiently. These mini-frameworks save lots of time, and if done right can make an application super simple to maintain down the road. Plug 'n Play for the win!

참고URL : https://stackoverflow.com/questions/1089327/what-programming-practice-that-you-once-liked-have-you-since-changed-your-mind-a

반응형