How do I break my procedural coding habits? [closed]

我是研究僧i 提交于 2019-12-20 09:55:10

问题


I recently read an interesting comment on an OOP related question in which one user objected to creating a "Manager" class:

Please remove the word manager from your vocabulary when talking about class names. The name of the class should be descriptive of its' purpose. Manager is just another word for dumping ground. Any functionality will fit there. The word has been the cause of many extremely bad designs

This comment embodies my struggle to become a good object-oriented developer. I have been doing procedural code for a long time at an organization with only procedural coders. It seems like the main strategy behind the relatively little OO code we produce is to break the problem down into classes that are easily identifiable as discrete units and then put the left over/generalized bits in a "Manager" class.

How can I break my procedural habits (like the Manager class)? Most OO articles/books, etc. use examples of problems that are inherently easy to transform into object groups (e.g., Vehicle -> Car) and thus do not provide much guidance for breaking down more complex systems.


回答1:


First of all, I'd stop acting like procedural code is wrong. It's the right tool for some jobs. OO is also the right tool for some jobs. So is functional. Each paradigm is just a different point of view of computation, and exists because it's convenient for certain problems, not because it's the only right way to program. In principle, all three paradigms are mathematically equivalent, so use whichever one best maps to the problem domain. IMHO, if using a multiparadigm language it's even ok to blend paradigms within a module if different subproblems are best modeled by different worldviews.

Secondly, I'd read up on design patterns. It's hard to understand OO without some examples of the real-world problems it's good for solving. Head First Design Patterns is a good read, as it answers a lot of the "why" of OO.




回答2:


Becoming good at OO takes years of practice and study of good OO code, ideally with a mentor. Remember that OO is just one means to an end. That being said, here are some general guidelines that work for me:

  • Favor composition over inheritance. Read and re-read the first chapter of the GoF book.
  • Obey the Law of Demeter ("tell, don't ask")
  • Try to use inheritance only to achieve polymorphism. When you extend one class from another, do so with the idea that you'll be invoking the behavior of that class through a reference to the base class. ALL the public methods of the base class should make sense for the subclass.
  • Don't get hung up on modeling. Build a working prototype to inform your design.
  • Embrace refactoring. Read the first few chapters of Fowler's book.



回答3:


The single responsibility principle helps me break objects into manageable classes that make sense.

Each object should do one thing, and do it well without exposing how it works internally to other objects that need to use it.




回答4:


A 'manager' class will often:

  1. Interogate something's state
  2. Make a decision based on that state

As an antidote or contrast to that, Object-Oriented design would encourage you to design class APIs where you "tell don't ask" the class itself to do things itself (and to encapsulate its own state): for more about "tell don't ask" see e.g. here and here (and maybe someone else has a better explanation of "tell don't ask" but these are first two articles that Google found for me).

It seems like the main strategy the little OO code we produce is to break the problem down into classes that are easily identifiable as discrete units and then put the left over/generalized bits in a "Manager" class.

That may well be true even at the best of times. Coplien talked about this towards the end of his Advanced C++: Programming Styles and Idioms book: he said that in a system, you tend to have:

  • Self-contained objects
  • And, "transactions", which act on other objects

Take, for example, an airplane (and I'm sorry for giving you another vehicular example; I'm paraphrasing him):

  • The 'objects' might include the ailerons, the rudder, and the thrust
  • The 'manager' or autpilot would implement various commands or transactions

For example, the "turn right" transaction includes:

  • flaps.right.up()
  • flaps.left.down()
  • rudder.right()
  • thrust.increase()

So I think it's true that you have transactions, which cut across or use the various relatively-passive 'objects'; in an application, for example, the "whatever" user-command will end up being implemented by (and therefore, invoking) various objects from every layer (e.g. the UI, the middle layer, and the DB layer).

So I think it's true that to a certain extent you will have 'bits left over'; it's a matter of degree though: perhaps you ought to want as much of the code as possible to be self-contained, and encapsulating, and everything ... and the bits left over, which use (or depend on) everything else, should be given/using an API which hides as much as possible and which does as much as possible, and which therefore takes as much responsibility (implementation details) as possible away from the so-called manager.

Unfortunately I've only read of this concept in that one book (Advanced C++) and can't link you to something online for a clearer explanation than this paraphrase of mine.




回答5:


Reading and then practicing OO principles is what works for me. Head First Object-Oriented Analysis & Design works you through examples to make a solution that is OO and then ways to make the solution better.




回答6:


You can learn good object-oriented design principles by studying design patterns. Code Complete 2 is a good book to read on the topic. Naturally, the best way to ingrain good programming principles into your mind is to practice them constantly by applying them to your own coding projects.




回答7:


How can I break my procedural habits (like the Manager class)?

Make a class for what the manager is managing (for example, if you have a ConnectionManager class, make a class for a Connection). Move everything into that class.

The reason "manager" is a poor name in OOP is that one of the core ideas in OOP is that objects should manage themselves.

Don't be afraid to make small classes. Coming from a procedural background, you may think it isn't worth the effort to make a class unless it's a thousand lines of code and is some core concept in your domain. Think smaller. A ten line class is totally valid. Make little classes where you see they make sense (a Date, a MailingAddress) and then work your way up by composing classes out of those.

As you start to partition little pieces of your codebase into classes, the remaining procedural code soup will shrink. In that shrinking pool, you'll start to see other things that can be classes. Continue until the pool is empty.




回答8:


How many OOP programmers does it take to change a light bulb?

None, the light bulb changes itself.

;)




回答9:


You can play around with an OO language that has very bad procedural support like Smalltalk. The message sending paradigm will force you into OO thinking.




回答10:


i think you should start it with a good plan. planning using CLASS Diagrams would be a good start.

you should identify the ENTITIES needed in the applicaiton, then define each entitie's ATTRIBUTES, and METHODS. if there are repeated ones, you could now re-define your entities in a way that inheritance could be done, to avoid redundancy. :D.




回答11:


I have a three step process, this is one that I have gone through successfully myself. Later I met an ex-teacher turned programmer (now very experienced) who explained to me exactly why this method worked so well, there's some psychology involved but it's essentially all about maintaining control and confidence as you learn. Here it is:

  1. Learn what test driven development (TDD) is. You can comfortably do this with procedural code so you don't need to start working with objects yet if you don't want to. The second step depends on this.

  2. Pick up a copy of Refactoring: Improving the Design of Existing Code by Martin Fowler. It's essentially a catalogue of little changes that you can make to existing code. You can't refactor properly without tests though. What this allows you to do is to mess with the code without worrying that everything will break. Tests and refactoring take away the paranoia and sense that you don't know what will happen, which is incredibly liberating. You left to basically play around. As you get more confident with that start exploring mocks for testing the interactions between objects.

  3. Now comes the big that most people, mistakenly start with, it's good stuff but it should really come third. At this point you can should reading about design patterns, code smells (that's a good one to Google) and object oriented design principles. Also learn about user stories or use cases as these give you good initial candidate classes when writing new applications, which is a good solution to the "where do I start?" problem when writing apps.

And that's it! Proven goodness! Let me know how it goes.




回答12:


My eureka moment for understanding object-oriented design was when I read Eric Evans' book "Domain-Driven Design: Tackling Complexity in the Heart of Software". Or the "Domain Driven Design Quickly" mini-book (which is available online as a free PDF) if you are cheap or impatient. :)

Any time you have a "Manager" class or any static singleton instances, you are probably building a procedural design.



来源:https://stackoverflow.com/questions/559786/how-do-i-break-my-procedural-coding-habits

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!